Live data from Hacker News

Zero-cost futures in Rust

aturon.github.io

111–120 of 348 posts

Re: Zero-cost futures in Rust

#111
post #84

As mentioned in the post, given Rust wants to operate in the same space as C, this approach makes sense. However from a higher level, building more complex concurrent systems, dealing with futures/deferred-s/promises and/or a central select/epoll/kqueue reactor loop gets daunting and doesn't mix with complex business rules. Deferred based approach has been a round for many years. I experienced it by using Twisted (Py…

> So wondering if Rust provides any ability to add that kind of an N:M threading approach. Perhaps via an extension, macro or some other mechanism.

I don't want M:N threading as Go implements it. It's a big loss of performance for marginal benefit over futures. In particular the libmill approach was tried in Rust and the results were far worse than 1:1.

However, assuming this takes off I would like to see async/await style syntactic sugar over futures down the road to make it easier to write code that looks blocking but actually isn't. Crucially, this sugar would maintain the zero-cost nature of futures. With that approach, we'd have the ergonomics of languages like Erlang and Go without the significant performance tax associated with M:N.

Re: Zero-cost futures in Rust

#112
post #26

Earlier quoted context omitted.

Yes , i only have a simple understanding of rust memory model . So what happened when/if the future escapes/outlives the current stack/context ?

To be clear, the issue here isn't so much stack vs heap, as much as how many heap allocations are happening. In practice, you build up a really big combined future on the stack, which has all of the space needed for any state in its state machine, and then when the future is fired off (in a task -- one per connection), that entire thing is moved into the heap in one shot. Thus, generally, you do one big allocation up…

Fair enough, but op was quite misleading by saying that in rust closure don't need allocation.

So back to future vs coroutine , it seems that they the advantage in term of allocation simply because the context is not distroid when suspending/resuming coroutines

Re: Zero-cost futures in Rust

#113
post #84

As mentioned in the post, given Rust wants to operate in the same space as C, this approach makes sense. However from a higher level, building more complex concurrent systems, dealing with futures/deferred-s/promises and/or a central select/epoll/kqueue reactor loop gets daunting and doesn't mix with complex business rules. Deferred based approach has been a round for many years. I experienced it by using Twisted (Py…

In other words futures are not as composable as one would hope. John Reppy's CML seems like a much better toolbox which gets composability without pretension. Vesa Karvonen (whom I understand has worked on the MLTon compiler) has offered an excellent delivery in Hopac for C# and F# complete with a slew of combinators: https://github.com/Hopac/Hopac I'm not aware of anyone offering an alternative superior to an inform…

I think Rust's approach here makes a lot more sense for the language than Go/CML style M:N would. You can recover most of the M:N ergonomics over time via async/await style syntax. But if your foundation is built on a (comparatively) slow "pthreads in userland" threading model, then you hit a performance ceiling that you can never break through. For a language like Rust, it makes sense to begin in the optimum place and then layer zero-cost abstractions on top to achieve the right ergonomics.

Re: Zero-cost futures in Rust

#114
post #26

Earlier quoted context omitted.

To be clear, the issue here isn't so much stack vs heap, as much as how many heap allocations are happening. In practice, you build up a really big combined future on the stack, which has all of the space needed for any state in its state machine, and then when the future is fired off (in a task -- one per connection), that entire thing is moved into the heap in one shot. Thus, generally, you do one big allocation up…

Fair enough, but op was quite misleading by saying that in rust closure don't need allocation. So back to future vs coroutine , it seems that they the advantage in term of allocation simply because the context is not distroid when suspending/resuming coroutines

  let mut counter = 0;
  let mut increment = || { counter += 1; counter };

  increment();
  increment();
There is no heap allocation there.

Re: Zero-cost futures in Rust

#115
post #84

As mentioned in the post, given Rust wants to operate in the same space as C, this approach makes sense. However from a higher level, building more complex concurrent systems, dealing with futures/deferred-s/promises and/or a central select/epoll/kqueue reactor loop gets daunting and doesn't mix with complex business rules. Deferred based approach has been a round for many years. I experienced it by using Twisted (Py…

In other words futures are not as composable as one would hope. John Reppy's CML seems like a much better toolbox which gets composability without pretension. Vesa Karvonen (whom I understand has worked on the MLTon compiler) has offered an excellent delivery in Hopac for C# and F# complete with a slew of combinators: https://github.com/Hopac/Hopac I'm not aware of anyone offering an alternative superior to an inform…

> I'm not aware of anyone offering an alternative superior to an informal CSP yet which seems to be the reason why Go and Clojure have picked it as well for their concurrency model.

What about Quasar [0] on the JVM?

0 - http://docs.paralleluniverse.co/quasar/

Re: Zero-cost futures in Rust

#116

What's the meaning of "zero cost future" in this context? I googled the phrase and got a bunch of irrelevant material.

  > C++ implementations obey the zero-overhead principle: What 
  > you don’t use, you don’t pay for [Stroustrup, 1994]. And 
  > further: What you do use, you couldn’t hand code any better.
  > 
  > – Stroustrup
So, in this context, the idea is that if you hand-rolled your own state machine, you should see no difference than using this library. And, we measured: the overhead in a benchmark comparing the two was 0.3%, that's three tenths of one percent.

Re: Zero-cost futures in Rust

#117
> a simple TCP echo server;

How convenient. I've been exploring/learning Rust, and writing a simple echo server and comparing it to a reference version I've written in Perl is my first semi-trivial program I wanted to do to compare.

Re: Zero-cost futures in Rust

#118
post #84

As mentioned in the post, given Rust wants to operate in the same space as C, this approach makes sense. However from a higher level, building more complex concurrent systems, dealing with futures/deferred-s/promises and/or a central select/epoll/kqueue reactor loop gets daunting and doesn't mix with complex business rules. Deferred based approach has been a round for many years. I experienced it by using Twisted (Py…

> So wondering if Rust provides any ability to add that kind of an N:M threading approach. Perhaps via an extension, macro or some other mechanism. I don't want M:N threading as Go implements it. It's a big loss of performance for marginal benefit over futures. In particular the libmill approach was tried in Rust and the results were far worse than 1:1. However, assuming this takes off I would like to see async/await…

Are libmill and Go's approach the same? I.e. Holding concurrent state in multiple stack frames? What causes that to have degraded performance?

Is this new approach different because instead of stack frames you just have dynamically allocated callback state?

Re: Zero-cost futures in Rust

#119

Earlier quoted context omitted.

Fair enough, but op was quite misleading by saying that in rust closure don't need allocation. So back to future vs coroutine , it seems that they the advantage in term of allocation simply because the context is not distroid when suspending/resuming coroutines

let mut counter = 0; let mut increment = || { counter += 1; counter }; increment(); increment(); There is no heap allocation there.

This is missing his point. "Increment" is called outside of its scope when the epoll triggers. If "counter" is stack allocated that would cause a segfault, so it must be heap allocated which is his point.

Re: Zero-cost futures in Rust

#120
post #74

Earlier quoted context omitted.

Yeah, using closures in zero-cost abstractions (like iterator or now future adaptors) does make compilation slow. LLVM isn't used to this kind of code, and takes time optimizing it. However, now that we have MIR we can optimize this on the Rust side first, before the type info has been lost. This was one of the reasons MIR was added :)

I'm... curious about why you think LLVM isn't used to the sort of code that results from these sort of zero-cost abstractions: C++ code is also very aggressive about templates that inline away to nothing, and modern C++ especially has many similar abstractions to Rust (cf. closures, and the range proposal). Rust isn't special in that particular regard. Maybe you mean LLVM is very low-level and thus it sees everything…

I believe he meant, lots of closures. Which is not normal in C or C++, but is the normal in Rust because they are Zero-Cost.

Without knowing anything about LLVM's internals, I would assume it doesn't anticipate so much closure chaining, and therefore doesn't leverage the fact that they are so easy to inline.

Post reply on HN