4 ms·
While coroutines may help in writing more maintainable/readable code, they make for a very inefficient structure since they have to keep a separate stack. Havin
by nimrody 17y ago
While coroutines may help in writing more maintainable/readable code, they make for a very inefficient structure since they have to keep a separate stack. Having many concurrent coroutines is probably a bad idea.
This is the classic trade-off between event based processing (state machines) and process based models.
- aaronblohowiak 17y agoMemory efficient or time efficient?
- nimrody 17y agoMemory of course. I don't think there's much of a difference in runtime (ignoring cache misses, etc.)
- jrockway 17y agoThere is not that much overhead. If you are writing an event-based network server, you have to allocate one structure of some type per connection, this is going to use memory regardless of whether it's a coroutine, or just a closure or instance of a class. If your coroutine implementation is good, these representations will be exactly equivalent. (In the real world, it is not as good of course, but it is theoretically possible to make coroutines as space efficient as hand-crafted state machines.) I did an experiment; I created 100,000 coroutines in Perl (with the Coro module) each implementing a simple network protocol (echo). This used about 14k of RAM per "connection". So sure, you could do it with less, but I know a lot of people who are happy with using 1.4G of RAM handling three concurrent requests -- this handles 100 thousand. (Right now, my web browser is using half that amount of memory so I can type this post.) And BTW, this is also not too expensive CPU-wise; under the hood it uses epoll on my machine, which scales linearly over the active connections. With most of the connections idle, this results in very good performance. Edit: I did the same thing with GHC and Control.Concurrent's forkIO; the overhead is about 3k per thread. Very reasonable.
- silentbicycle 17y agoAs a data point, creating 100,000 coroutines in Lua uses about 183 MB* , which works out to about 1.9K apiece. This seems independent of the function included in the coroutine -- "return 3" and a function with several pages of code use the same space. It's probably a small stack, a closure for "upvaues", and a function pointer. Note that this doesn't include memory for the IO connection, but the original question was about the space overhead of coroutines themselves. How much do Perl and Haskell use without the IO handle? * On an AMD64 running OpenBSD 4.6. On an i386 (32-bit) system, it took 142 MB.
- jrockway 17y agoWith empty suspended coros, we use about 169M for 300,000 of them. So that's about .5K per coroutine. In Haskell, 500,000 threads waiting for an empty mvar used about 1.4G of RAM. But if they just spin forever (foo = foo), not waiting for anything, then it uses 129M for 500,000 threads; .2K each. So really, coroutines are not costly at all. Most of the price you pay you would have to pay anyway. The overhead of the coroutine itself is tiny.
- silentbicycle 17y agoGood to know, thanks for the quick response.
- jrockway 17y agoAnd just for the record, my examples were on a 64 bit machine.