4 ms·
> Supporting truly massive concurrency requires another optimization: Only schedule a thread when you know it can do useful work! The problem is the scheduler
by omazurov 8y ago
> Supporting truly massive concurrency requires another optimization: Only schedule a thread when you know it can do useful work!
The problem is the scheduler doesn't know when a goroutine can do useful work. It thinks that if a new value arrives to a channel there is a good chance the goroutine will do something useful but that's not the case in general. My favorite example is Game of Life (CA) implemented as a network of goroutines communicating their state changes through channels: you have to collect 8 updates from predecessors to update your state, meaning you'll be scheduled to run 8 times before you finally make a real progress. Not good for scalability.
- jerf 8y agoI'd point out everything in your example is a characteristic of the program, not the runtime. There isn't any other runtime or compiler than is going to do significantly better, or at least I'm not aware of any. Regardless of language, if you want to be high-performance on that task, you're going to want to chunk your game world into tiles and dispatch tiles to workers, for all kinds of reasons, or something similar. (Assuming you even win from concurrency at all since this is on the borderline of where a single CPU may be able to keep up with RAM streaming speeds, assuming modestly clever encoding. And assuming a straightforward implementation rather than HashLife, etc.) It's true that it's hard for a scheduler to "know" that useful work is going to be done, but that's just a fact of life, just like the CPU doesn't "know" whether or not you're going to use the next page of RAM or go flying off in an effectively random direction.
- benwilson-512 8y agoIn Erlang (and presumably Go) green threads end up in a waiting queue when waiting on further work to do, and as such don't need to be polled or consume any CPU at all while idle. It's only when they receive a message indicating more work can be done that they move into the work queue.
- chrisseaton 8y agoI think the person you're replying to was saying that 'useful work' does not including waking up, reading one value, and then immediately sleeping again for another response. That's a big expensive context switch for really nothing very useful, and it could have waited until all inputs were ready and there was significant computation that could be run.
- Ndymium 8y agoIn most cases, BEAM's (the Erlang VM's) context switches are not big and expensive, though, which is something you get with user space threads.
- gpderetta 8y agoUse one channel per neighbor and have a wait all primitive that wakes the coroutine when all its inputs are ready. I don't know if go has such a primitive and if its implementation is optimized in such a way or simply waits for each channel in sequence.