5 ms·
Having made "async" the default, you've just returned to regular threading, which is what we should have stuck with all along. The thread model is actually pret
by quotemstr 8y ago
Having made "async" the default, you've just returned to regular threading, which is what we should have stuck with all along. The thread model is actually pretty useful, the pitfalls are well understood, and the tooling very mature.
- noobermin 8y agoI feel like you're making a very interesting point but it seems a bit broad and abstract for me to justify in my head. Could you clarify what you mean?
- ploxiln 8y agoIf you want easier concurrency with higher overhead, that's exactly what OS threads do. The OS kernel is the "event loop" in this case, and they're highly optimized for this, though there is some overhead which is hard to avoid. Rust has gone back and forth on this. Pre-1.0 versions of Rust had a "green threads" mode. It was removed in favor of OS threads because it wasn't worth the complexity. Go is a language in which "all functions are async" and it's pretty cool. But it needs a runtime, and interop with C / C++ has some real overhead related to switching to a C-style stack. Rust did not want to make those compromises, it wanted to be appropriate for bare-metal or kernel programming, and for libraries used by big high-performance C++ applications. In these cases, Go's model does not work well. I personally use Go a lot, it's great for network services and command-line tools, and that's mostly what I do.
- deleted 8y ago[deleted]
- weberc2 8y ago> In these cases, Go's model does not work well. I don't think there's anything about Go's concurrency model that precludes bare metal; I think it's just that the maintainers didn't want to support a bare metal runtime. In fact, I recall at least one other project that modified Go's runtime to support exactly this. I'm also not sure how much of the C interop overhead is due to the different stack models and how much is due to GC concerns or other things. But generally I agree with you--in practice Rust is well suited for these types of tasks and Go is not.
- gpderetta 8y ago> Go is a language in which "all functions are async" and it's pretty cool. Async has come to signify a very specific implementation strategy (i.e. stackless coroutines). Go definitely went in another direction.
- pcwalton 8y agoThis is a very even-handed and fair description of the tradeoffs involved, something that is all-too-often missing in this space. Thanks for describing it so well.
- anko 8y agoThreading sucks. It's a situation where you have some external process (the operating system) deciding when different pieces of work should be woken up, with no way of feeding this back (so it just bases it on relatively naive schedulers). In practice, most of your threads are in one form of wait loop or another and you've just got polling both inside the threads and with the scheduler. Have a look at Erlang if you want a better model :) the erlang "processes" (different to os processes) can intelligently only wake up when there is work for them to do. For a language to efficiently use cores, it really needs to include it's own scheduling.
- millstone 8y agoWhy would kernel threads be polling in practice? Won't most be waiting on locks, file descriptors, timers, etc?
- anko 8y agoYou're right, in theory, if your select() or epoll() doesn't have a timeout. And the threads aren't doing any active work. But if you're optimising for that state, then you don't care about inefficiencies of one model or another. There are also costs in setting and checking those locks etc. Sure, you can build solutions to optimise a broken model, which we've done over decades (with quite a bit of success!), but it doesn't make the model less broken.
- xfer 8y ago> But if you're optimising for that state, then you don't care about inefficiencies of one model or another. Sure you do, there is noticable memory and ctx switching overhead(for large no. of them ofc) in stackful coroutines.
- weberc2 8y agoTo pick some nits and generally elaborate, Erlang's VM also has a scheduler; it's not the presence or lack of a scheduler, it's how efficient it is and what guarantees it allows the programmer to make about their system. For example, OS schedulers are typically pre-emptive, which means your OS thread can get interrupted anywhere. On the otherhand, Go's scheduler (I'm using Go because I'm more familiar with it than with Erlang) only allows context switching at well-defined points in your program. Further, operating system threads have more overhead than in Go (presumably also Erlang) because they're fixed stack size (yes, I know this isn't true for all OSes).
- gpderetta 8y agoFWIW, Scheme (among others) has async by default on steroids (aka call/cc) and is nothing like regular threading. You can build threading on top of it but also all kind of other abstractions.