操作系统中的轻量级线程
据说 Node(以及可能的twisted 等)相对于更传统的线程服务器的主要好处之一是事件循环模型实现的非常高的并发性。最大的原因是每个线程都有较高的内存占用,并且交换上下文的成本相对较高。当您有数千个线程时,服务器花费大部分时间在线程之间交换。
我的问题是,为什么操作系统或底层硬件不支持更轻量级的线程?如果他们这样做了,你能用普通线程解决 10k 问题吗?如果他们不能,那是为什么?
It is said that one of the main benefits of Node (and presumable twisted et al) over more conventional threaded servers, is the very high concurrency enabled by the event loop model. The biggest reason for this is that each thread has a high memory footprint and swapping contexts is comparatively expensive. When you have thousands of threads the server spends most of its time swapping from thread to thread.
My question is, why don't operating systems or the underlying hardware support much more lightweight threads? If they did, could you solve the 10k problem with plain threads? If they can't, why is that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
现代操作系统可以支持大量线程的执行。
更一般地说,硬件变得越来越快(最近,它的速度越来越快,其方式对多线程和多处理比对单线程事件循环更友好——即增加了内核数量,而不是增加了处理吞吐量能力)单核)。如果您今天无法承受线程的开销,那么明天您可能就可以承受。
Twisted(大概还有 Node.js 等)的协作多任务系统相对于抢占式多线程(至少以 pthread 的形式)提供的是易于编程。
正确使用多线程需要比正确使用单线程更加小心。事件循环只是在不超出单线程的情况下完成多项事情的方法。
考虑到并行硬件的激增,多线程或多处理变得更容易执行(并且更容易正确执行)将是理想的选择。 Actor、消息传递,甚至 Petri 网都是人们尝试解决这个问题的一些解决方案。与主流多线程方法(pthreads)相比,它们仍然非常边缘。另一种方法是 SEDA,它使用多个线程来运行多个事件循环。这也没有流行起来。
因此,使用事件循环的人可能认为程序员的时间比 CPU 时间更有价值,而使用 pthread 的人可能做出相反的决定,而探索 Actor 等的人希望更加重视这两种时间(显然疯了,这可能就是为什么没人听他们的原因)。
Modern operating systems can support the execution of a very large number of threads.
More generally, hardware keeps getting faster (and recently, it has been getting faster in a way that is much friendlier to multithreading and multiprocessing than to single-threaded event loops - ie, increased number of cores, rather than increased processing throughput capabilities in a single core). If you can't afford the overhead of a thread today, you can probably afford it tomorrow.
What the cooperative multitasking systems of Twisted (and presumably Node.js et al) offers over pre-emptive multithreading (at least in the form of pthreads) is ease of programming.
Correctly using multithreading involves being much more careful than correctly using a single thread. An event loop is just the means of getting multiple things done without going beyond your single thread.
Considering the proliferation of parallel hardware, it would be ideal for multithreading or multiprocessing to get easier to do (and easier to do correctly). Actors, message passing, maybe even petri nets are some of the solutions people have attempted to solve this problem. They are still very marginal compared to the mainstream multithreading approach (pthreads). Another approach is SEDA, which uses multiple threads to run multiple event loops. This also hasn't caught on.
So, the people using event loops have probably decided that programmer time is worth more than CPU time, and the people using pthreads have probably decided the opposite, and the people exploring actors and such would like to value both kinds of time more highly (clearly insane, which is probably why no one listens to them).
问题并不在于线程的重量有多大,而在于要编写正确的多线程代码,您需要对共享项进行锁定,并且这会阻止它随着线程数量的增加而扩展,因为线程最终会等待彼此获得锁定,而您快速达到添加额外线程不起作用的程度,甚至随着更多的锁争用而减慢系统速度。
在许多情况下,您可以避免锁定,但很难做到正确,有时您只需要一个锁。
因此,如果您仅限于少量线程,您可能会发现,完全消除必须锁定资源的开销,甚至考虑一下,无论您有多少个线程,单线程程序都比多线程程序更快。添加。
基本上,锁(取决于您的程序)可能非常昂贵,并且可以阻止您的程序扩展到几个线程之外。而且您几乎总是需要锁定某些东西。
问题不是线程的开销,而是线程之间的同步。即使您可以立即在线程之间切换,并且拥有无限的内存,如果每个线程最终都在队列中等待某些共享资源,那么这也没有任何帮助。
The issue isn't really how heavyweight the threads are but the fact that to write correct multithreaded code you need locks on shared items and that prevents it from scaling with the number of threads because threads end up waiting for each other to gain locks and you rapidly reach the point where adding additional threads has no effect or even slows the system down as you get more lock contention.
In many cases you can avoid locking, but it's very difficult to get right, and sometimes you simply need a lock.
So if you are limited to a small number of threads, you might well find that removing the overhead of having to lock resources at all, or even think about it, makes a single threaded program faster than a multithreaded program no matter how many threads you add.
Basically locks can (depending on your program) be really expensive and can stop your program scaling beyond a few threads. And you almost always need to lock something.
It's not the overhead of a thread that's the problem, it's the synchronization between the threads. Even if you could switch between threads instantly, and had infinite memory none of that helps if each thread just ends up waiting in a queue for it's turn at some shared resource.