Live data from Hacker News

Zero-cost futures in Rust

aturon.github.io

91–100 of 348 posts

Re: Zero-cost futures in Rust

#91
post #82

How does the zero-cost abstraction work? Say we make a Future and then chain `.map(|x| x+1)` on a dynamic number of times (N). Presumably this requires storing at least N function pointers. How can we store these N function pointers with zero cost? If it only takes one allocation, where does the N-1 future store its function pointers?

Each chain produces a different static type. If you want to do a dynamic amount of chains (which seems strange to me? Got an example?) you would need to allocate and use dynamic dispatch, yes. Basically `MyFuture.map(x)` => `Map ` `MyFuture.map(x).map(y)` => `Map , Y>` This is obviously disgusting to expose to users, which is one of the reasons this post uses the `impl Trait` syntax to cover it up and say "well it's…

Thanks for your answer. Here's a more realistic example. Say we have a file.close() function that returns a Future, indicating when the close is complete. Now we want to make a Future for closing a list of files:

    let fut = Future::new();
    let v = vec![file, file2, file3];
    for file in v.into_iter() {
        fut = fut.and_then(file.close());
    }
Is this possible with this API, or would the assignment to `fut` break because we now have a different type?

With traditional Futures I'd expect this to look like a sort of linked-list of closures (definitely lots of allocation). What does it end up looking like under the hood with zero-cost Rust futures?

Re: Zero-cost futures in Rust

#92

I'm rather surprised by the benchmark; I would expect the Go benchmark to be faster than Java (and the fact that it isn't may indicate some improvements that can be done to fasthttp by learning from rapidoid or minihttp). Then again, the difference isn't that much, so it just could be implementation details that would require a total refactor to fix.

other test: techempower benchmarks

https://www.techempower.com/benchmarks/#section=data-r12&hw=...

Re: Zero-cost futures in Rust

#93
post #82

Earlier quoted context omitted.

Each chain produces a different static type. If you want to do a dynamic amount of chains (which seems strange to me? Got an example?) you would need to allocate and use dynamic dispatch, yes. Basically `MyFuture.map(x)` => `Map ` `MyFuture.map(x).map(y)` => `Map , Y>` This is obviously disgusting to expose to users, which is one of the reasons this post uses the `impl Trait` syntax to cover it up and say "well it's…

Thanks for your answer. Here's a more realistic example. Say we have a file.close() function that returns a Future , indicating when the close is complete. Now we want to make a Future for closing a list of files: let fut = Future ::new(); let v = vec![file, file2, file3]; for file in v.into_iter() { fut = fut.and_then(file.close()); } Is this possible with this API, or would the assignment to `fut` break because we…

As discussed elsewhere in this thread, the most direct translation of that code would also be a linked list of futures, but I don't see an alternative for that sort of structure in general (i.e. every scheme for this sort of asynchrony will have a dynamic chain of allocations).

However, the library does provide various abstractions that can abbreviate certain patterns and do them more efficiently than otherwise, e.g. http://alexcrichton.com/futures-rs/futures/fn.collect.html for this case.

Re: Zero-cost futures in Rust

#94
post #82

Earlier quoted context omitted.

Each chain produces a different static type. If you want to do a dynamic amount of chains (which seems strange to me? Got an example?) you would need to allocate and use dynamic dispatch, yes. Basically `MyFuture.map(x)` => `Map ` `MyFuture.map(x).map(y)` => `Map , Y>` This is obviously disgusting to expose to users, which is one of the reasons this post uses the `impl Trait` syntax to cover it up and say "well it's…

Thanks for your answer. Here's a more realistic example. Say we have a file.close() function that returns a Future , indicating when the close is complete. Now we want to make a Future for closing a list of files: let fut = Future ::new(); let v = vec![file, file2, file3]; for file in v.into_iter() { fut = fut.and_then(file.close()); } Is this possible with this API, or would the assignment to `fut` break because we…

You are correct in assuming that the assignment would be a type error.

Similar to other languages, you'd have to allocate. In rust, it would probably look like:

    let mut fut: Box> = Box::new(Future::new());
and then

    fut = Box::new(fut.and_then(|| file.close()));

Re: Zero-cost futures in Rust

#95
post #20

Is there any special handling for Futures that complete with an error? Also, how do you debug code that's hung or taking too long? It might be useful to get a list of all the jobs (incomplete Futures) that are currently running, much like running 'ps'.

Yes -- the blog post didn't go into details about this, but Futures in general have an error type as well, and all the combinators know how to propagate errors correctly. (There's also a notion of "cancellation" for a future -- we'll get into this with later posts). In terms of debugging, there's not infrastructure currently, but the kind of thing you're talking about should be easy to add!

I've used async tooling extensively on several platforms now, including Go, C#, Java, Clojure's core async, the new async methods in JS.

The challenge of these state machine codegen abstractions is not performance. It's making source-facing debuggers do the right thing and handle errors in a way that doesn't break the illusion that the code running is the code in source.

If you can match the degree of support C# has for error handling, you'll be in an amazing place.

Re: Zero-cost futures in Rust

#96
Unfortunately, it seems that you still need to use callbacks and lots of and_thens to write this async code.

Wouldn't it be possible to add coroutines to Rust instead?

Re: Zero-cost futures in Rust

#97

TLDR; I’ve claimed a few times that our futures library provides a zero-cost abstraction, in that it compiles to something very close to the state machine code you’d write by hand. To make that a bit more concrete: - None of the future combinators impose any allocation. When we do things like chain uses of and_then, not only are we not allocating, we are in fact building up a big enum that represents the state machin…

And in practice:

> ...we’ve added a comparison of minihttp against a directly-coded state machine version in Rust. The two are within 0.3% of each other.

Re: Zero-cost futures in Rust

#99

This is awesome, but I have an off-topic rust question: Why can't we have some syntactic sugar to get rid of .unwrap()?

For Result, in nightly, there is sugar, though it's for try!, not unwrap(), which serve very similar purposes.

It's not yet clear if said sugar will support Option; that's one of the reasons it's not stable yet.

Feel free to post off-topic questions on https://users.rust-lang.org/ any time!

Post reply on HN