6 ms·
Node suffers similar problems, although I would describe them differently to the author. Essentially: 1. All Node's async IO is lumped together into the same
by jorangreef 8y ago
Node suffers similar problems, although I would describe them differently to the author.
Essentially:
1. All Node's async IO is lumped together into the same threadpool.
2. There is no distinction between the nature of each async IO task.
3. Async CPU tasks (fs.stat hitting the fs cache, async multi-core crypto, async native addons) complete orders of magnitude faster than async disk tasks (SSD or HDD), and these can be orders of magnitude faster than async network tasks (dns requests to a broken dns server).
4. There are three basic async performance profiles, fast (CPU), slow (disk), very slow (dns), but Node has no concept of this.
5. This leads to the Convoy effect. Imagine what happens when you race trucks, cars, and F1... all on the same race track.
6. The threadpool has a default size of only 4 threads, on the assumption that this reflects the typical number of CPU cores (and reduces context switches).
7. 4 threads is a bad default because it leads to surprising behavior (4 slow dns requests to untrusted servers are enough to DoS the process).
8. 4 threads is a bad default because libuv's memory cost of 128 threads is cheap.
9. 4 threads is a bad default because it prevents the CPU scheduler from running async CPU tasks while slow disk and slower DNS tasks are running. Concurrent CPU tasks should rather be limited to the number of cores available, while concurrent disk and DNS tasks should be given more than the number of cores available (context switches are better amortized for these).
10. Because everything is conflated, hard concurrency limits can't be enforced on fast, slow or slower tasks. It's all or nothing.
There are efforts underway to support multiple threadpools in Node (a threadpool for fast tasks sized to the number of cores, a threadpool for slow tasks sized larger, and a threadpool for slower tasks also sized larger). The goal is to get to the point where we can have separate race tracks in Node, with F1, cars and trucks on separate race tracks, controlled and raced to their full potential:
https://github.com/libuv/libuv/pull/1726 https://github.com/libuv/libuv/pull/1726
- felixfbecker 8y agoThis is a common misconception. Node (libuv) only uses the thread pool as a last resort. Many operations nowadays have a native async OS API, so they don't need to use (and therefor don't block/fill) the thread pool. https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c#07f5 https://medium.com/the-node-js-collection/what-you-should-kn... https://stackoverflow.com/a/22644735/4208018 https://stackoverflow.com/a/22644735/4208018
- jorangreef 8y ago"Node (libuv) only uses the thread pool as a last resort." When did you last read deps/uv/src/win/fs.c or deps/uv/src/unix/fs.c? If by "last resort" you mean 99.9% of all async fs tasks, then I would agree with you.
- coder543 8y agoisn't that because OSes have broken async filesystem APIs that can't be trusted? But network requests (like dns) have well defined APIs for async, and should never be required to block a thread, and therefore do not need a threadpool.
- deleted 8y ago[deleted]