为什么“多路复用、非阻塞 I/O”比“基于线程、阻塞 I/O”更具可扩展性?

12
我正在阅读JDK 7文档中关于通道的内容(这里),并偶然发现了以下内容:

 

多路复用、非阻塞I/O,比面向线程、阻塞I/O更具可扩展性,[...]

为什么这样做要比阻塞式I/O更具扩展性,请给出一个简单的解释?

2个回答

6

因为线程堆栈通常比支持异步I/O连接所需的数据结构大得多。此外,调度数千个线程是低效的。


3
通常人们会这样说,但我的桌面电脑可以运行成千上万个线程,但我还没有看到过任何问题,能够从单台机器上服务成千上万的连接,而不是让一切都陷入停顿。因此,在我看来,这似乎是一个薄弱的论点。此外,使用带选择器的NIO非阻塞模式并不总是一个很好的选择。 - Voo
@Voo:有些连接可能会闲置数十分钟,但仍然保持打开状态。 - Ben Voigt
1
@Voo,我怀疑你是否真的拥有数万个可运行的线程(而不仅仅是空闲的)。即使上下文切换很便宜,仍然会有TLB缓存驱逐和更多的缓存失效。我自己处理数千个连接,我想说,在双插槽Xeon上为大约2k用户提供每秒85k条消息需要消耗20%的CPU(所有CPU的总和)...此外,NIO允许“公平”流量传递,这非常重要,但往往被忽视,因为它确保了客户端的稳定延迟。(如果我没记错的话,基准测试并不测量延迟) - bestsss
@bestsss 正如我所说,如果线程执行严重的工作,一切都会在阈值之前停滞不前。为了澄清:线程正在执行一些相当重量级的工作,因此我们在上下文切换开销成为问题之前就达到了单个服务器的容量。你是对的,我只测试了带宽(对我的问题更重要),我认为我还没有看到关于延迟的任何信息。这将成为一个有趣的基准测试 - 将来必须测试一下(还要测试阻塞NIO - 听说有一些好的东西)。 - Voo
@voo,使用多个线程无法确保公平的流量分配,因为它严重依赖于操作系统调度程序和连接客户端的网络速度。 - bestsss

3
“阻塞”意味着线程必须等待资源可用,这意味着定义上,线程将一直等待资源。非阻塞则避免了这种情况。
通常,非阻塞解决方案更加棘手,但它们避免了资源争用,这使得扩展变得更加容易。(也就是说,Channel的目的是让这个过程变得不那么棘手。)

1
非阻塞I/O并不意味着线程不等待,它只是意味着等待操作与I/O操作是分离的。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接