22 ms·
> CPUs can only execute about one logical thread per core truly concurrently.1 An inherent side effect: If you have more threads than cores, threads must be pau
by choxi 8y ago
> CPUs can only execute about one logical thread per core truly concurrently.1 An inherent side effect: If you have more threads than cores, threads must be paused to allow other threads to do work, then later resumed when it’s their turn again.
When would millions of goroutines be useful if you can only run ~4 threads in parallel?
- icebraining 8y agoIf you're a server with a million clients holding an open connection, you can have a goroutine for each, holding the connection state while waiting for them to communicate again.
- yen223 8y agoThis is especially important if you have long-lived connections, e.g. websockets.
- chrisseaton 8y ago> When would millions of goroutines be useful if you can only run ~4 threads in parallel? Concurrency. Have you heard of the 10k problem? Some people think the best way to handle tends of thousands of concurrent clients is to have each run in a lightweight thread (or goroutine, or whatever term for the same basic abstract concept.) This is as opposed to using an event-based system like Node.js does. Maybe they're right or maybe they're wrong, but that's where it's useful.
- jimmaswell 8y agoA bunch of threads on one core isn't that different from node handling the same number of events. Just moving some of the responsibility from the OS to a framework.
- chrisseaton 8y agoThe most critical difference is that threads can yield anywhere. Events only yield in well-defined places. Sometimes that's useful, sometimes it isn't. For example a thread can yield in the middle of a native call to something like zlib. If zlib doesn't know about your event framework (and it doesn't) then it can't yield.
- crimsonalucard 8y agoIO calls. Concurrency matters only if your threads are doing IO. Otherwise it's useless to use goroutines. Lets say an IO call to high latency connection takes 4 seconds. With no concurrency in between that IO call the program just sits and waits for a response. Under concurrency the program can switch to another thread while it's waiting for the IO call to complete.
- gpderetta 8y agoIt is not just for io. If a system is better modelled with a set of indipendent execution flows exchaging messages (a simulation for example), then coroutines are perfect. Games often use coroutines to model game entities: it is not a coincidence that lua has excellent coroutine support.
- crimsonalucard 8y agoRight, except that's not what's happening in reality no matter how you model it. Having your code mimic the actual pathway of execution rather than the overhead of simulating parallelism is more efficient. Typically multithreading adds way more complexity and a whole new class of bugs to the code.
- mikekchar 8y agoContinuations are different than concurrency. A continuation is useful for modelling a process that operates independently. You may or may not want the continuations to be running concurrently. One of the earliest uses of continuations in programming languages was in simulation and modelling. Imagine that you want to model a quarry. You have a pile of rocks, a rock crusher, a pile of gravel and a whole bunch of trucks. A truck takes a rock from the rock pile. it gives it to the crusher. The crusher works on the rock for a while and outputs some gravel. A truck takes the gravel to the gravel pile. You want to simulate different ways of scheduling the trucks so as to be optimal. You could write your simulation so that you update every object in your system at every time stamp, but that's really complicated and it also makes it really difficult to collect statistics about processes. Another way is to create a kind of "process" for each action in the system and a "resource" for each thing that could be used in the system. You then write the code for each process as a continuation and you request resources, blocking when they aren't available. Your overall simulation loop is very simple: it runs a single continuation until it requests a resource, and then it blocks. It then runs the next continuation until it requests a resource. Then it blocks. You just keep doing this, unblocking continuations when the resources become available (and all other continuations' simulation clocks are passed its current clock). The nice thing about this is that you need no concurrency at all -- or you can have a concurrent thread of execution for each continuation. The latter will obviously run faster, but that's not necessarily the point. The point is that the code was dramatically easier to write. For some kinds of simulation, a million continuations is not unreasonable at all. In fact, for a lot of applications it would be great if you could have a lot more.