4 ms·
Quickest summary: Rust async is >3x faster and lighter than Linux threads. This is a great accomplishment for Rust.
by jph 6y ago
Quickest summary: Rust async is >3x faster and lighter than Linux threads. This is a great accomplishment for Rust.
- mhh__ 6y agoIf you elide a bounds check from a function but still spend a billion cycles in a loop, you've made your code run ever so slightly faster but gained nothing in the big picture.
- shmerl 6y agoIt sound to me like comparing apples and oranges though. Parallelism (threads) and concurrency (aysnc in Rust) are not the same thing and can be actually used in combination.
- jashmatthews 6y agoYou can happily use pthreads for concurrency up to ~10k before reaching for async.
- andrewchambers 6y agoI read it as most people are over investing in async rust.
- rudedogg 6y agoWhat makes you think that? Looking at the summary it looks like async is better in every way.
- scottlamb 6y agoBetter or equal in all the ways measured. But some things aren't measured, maybe because they're obvious to the author or because they're harder to quantify. * Rust's async ecosystem [1] adds a lot of complexity over simple threaded code. * Rust's async ecosystem doesn't interoperate as easily with C libraries written in a simple threaded way. (And it's debatable which interoperates more easily with C libraries written with a different event loop.) * async tasks can't be preempted, so concurrency will fall off a cliff if they run on O(cpus) threads and involve long-running computations or accidental blocking. I think it's reasonable to ask if these numbers are enough better to justify all that, particularly given the disappointing "this advantage goes away if the context switch is due to I/O readiness". And to go back and argue pro-async for a moment, io_uring might eliminate that disappointing caveat. Then again, on the pro-thread side, there's Google's interesting fibers model that might solve some of these performance issues. [2] Also, "~17µs for a new kernel thread" is the wrong number, since you can avoid that cost with a simple thread pool. Personally I think some things are better written as async, but it's a mistake to impose it on everything. For example, if you're writing a web app in Rust, I think you're usually better off writing threaded request handlers and having a mechanism for them to interact with the async hyper code. The hyper code is better off as async because an Internet-facing server might have an enormous number of connections in keepalive state. [1] or maybe I should say ecosystems, plural, given the current tokio vs async-std divide. [2] https://lwn.net/Articles/826860/ https://lwn.net/Articles/826860/
- andrewchambers 6y agoasync rust is more complex with a larger dependency tree and is harder to write. You get a marginal to good benefit if you have a specific work load that I think most people don't really have.
- harikb 6y agoKeep in mind that a new async task doesn't create a new thread. So yes, "not creating a new thread" is 3x faster than "creating a thread". If the app layer can context switch using language level constructs, and do co-operative switching, then yes, one gets the 3x benefit. imho, whether the async executor and scheduler is performant enough to manage the tasks is what one should worry about.
- scoutt 6y agoI'm confused. If many async tasks are ran on a single thread, what the thread does when is blocked waiting for things to happen? Does it sleep? If so, a context switch takes place anyway. If not, what is the impact on GUI applications? If I have a main thread to manage my GUI, should I spin a new thread to run my async tasks? A modern microcontroller/microprocessor is inherently event driven (for example, on ARM, at the very bottom of the call stack there is a wait-for-event (WFE) or wait-for-interrupt (WFI) instruction). If async needs to be polled to run ("Futures are inert in Rust and make progress only when polled"[1]) this means my processor should be busy running these async tasks instead of waiting (WFE or WFI) as the result of a native call to one of the operating system functions (i.e. recv() on a socket). What is the impact on embedded battery-based systems? [1] https://rust-lang.github.io/async-book/01_getting_started/02_why_async.html#async-in-rust-vs-other-languages https://rust-lang.github.io/async-book/01_getting_started/02...
- jstrong 6y agoin rust, there is no built-in runtime, so it depends on which one you are using. the runtime (e.g. tokio) is responsible for polling the future. for network io, behind the scenes this is most likely utilizing epoll system calls. epoll mitigates context switch problem in a few ways, mostly because there is only one stack context to notify about new io events, instead of many.
- harikb 6y agopolling is only explained as a logical thing. In reality the given task is only marked to be woken up later. The later being some other point, while the same OS thread executing something else, when the executor determines that the idling task can be woken up. "Waking" is nothing but the same OS thread now switching to execute whatever it is that it is waking up. Main idea is that a 'scheduler/executor' at the runtime/language level that knows about the state of the program can (a) 'save' and 'restore' fewer things compared to an OS context switch. (b) co-operative stuff does not need to pay the cost of too many unnecessary pre-emptions
- platinumrad 6y agoNobody asked for a bad summary.