5 ms·
The solution suggested by that article is to use M:N threading, which was tried in Rust and turned out to be slower than plain old 1:1 threading. If you don't
by pcwalton 7y ago
The solution suggested by that article is to use M:N threading, which was tried in Rust and turned out to be slower than plain old 1:1 threading.
If you don't want to deal with async functions, then you can use threads! That's what they're there for. On Linux they're quite fast. Async is for when you need more performance than what 1:1 or M:N threading can provide.
- mamcx 7y ago> If you don't want to deal with async functions, then you can use threads! Truly? If some very popular lib become async (like actix, request, that I use), I can TRULY ignore it and not split my world in async/sync?
- pcwalton 7y agoYou can easily convert async to sync by just blocking on the result. The other way (sync to async) is more difficult and requires proxying out to a thread pool, but it's also doable.
- BatmanAoD 7y agoAn `async` function _can_ call blocking functions, of course, it just blocks the entire thread of execution which could otherwise continue making progress by polling another future.
- nemothekid 7y agoBoth actix and reqwest are already async, the fact that you haven't noticed yet just shows that you are already ignoring it.
- mamcx 7y agoBut the signatures are not. If them mark the types/functions async, what happened? I must rewrite all the calls?
- pas 7y agoAsync is just a syntactic sugar for Future<...>, you can poll() it manually. You can take the event loop, run it on one thread and do whatever you wish on other threads. Fearless concurrency, after all.
- bluejekyll 7y agoyou can just `.await` on any Future returned directly by APIs, if it's not marked as an async fn.
- deleted 7y ago[deleted]
- tomp 7y agoHow hard was it tried? I imagine there's a reason that languages like Go adopted M:N threading... obviously part of the reason is that it's way more scaleable, but userspace threading is also supposed to be faster, as context switches don't need to switch to kernel space... were the problems tight loops (which AFAIK is also the problem in Go)? or maybe it's just so much easier / more efficient if you also have GC...
- the_why_of_y 7y agoThe reason is that M:N threading inherently requires a language runtime, and the advantage of increased scalability (GHC threads use less than 1KB of memory) comes with the disadvantage that FFI calls are really quite expensive to do, because you need to move to a separate native thread in case the FFI call blocks. These languages (Erlang, Haskell, Go, ...) have no ambition to be useful for system programming; they're not intended as a replacement for C/C++ in that domain, unlike Rust.
- dunkelheit 7y agoIn my opinion they tried hard enough. Here are the links to the discussions of that time if you are into that kind of thing: https://mail.mozilla.org/pipermail/rust-dev/2013-November/006314.html https://mail.mozilla.org/pipermail/rust-dev/2013-November/00... https://mail.mozilla.org/pipermail/rust-dev/2013-November/006550.html https://mail.mozilla.org/pipermail/rust-dev/2013-November/00... https://github.com/rust-lang/rfcs/blob/master/text/0230-remove-runtime.md https://github.com/rust-lang/rfcs/blob/master/text/0230-remo... It is clear that they really wanted to make green threading work, but in the end it proved incompatible with other goals of the language. The main problem as I understand it is with the stack: you can't make the stack big from the beginning (or your threads wouldn't be lightweight anymore) so you need to grow it dynamically. If you grow it by adding new segments to the linked list, you get the "stack thrashing"/"hot split" problem: if you are unlucky and have to allocate/deallocate a segment in a tight loop the performance suffers horribly. Go solved the problem by switching to contiguous relocatable stacks: if there is not enough space in the stack, a bigger contiguous chunk of memory is allocated and old contents of the stack are copied there (a-la C++ vector). Now there is a problem with references to the stack-allocated variables - they become invalid. In go this problem is solvable because it is a managed garbage-collected language so they can simply rewrite all the references to point to the new locations but in rust it is infeasible.