我记得2或3年前阅读过几篇文章,其中人们声称现代线程库变得非常好,以至于每个请求线程的服务器不仅比非阻塞服务器更容易编写,而且它们是也更快。我相信甚至在Java中使用JVM将Java线程映射到pthreads(即Java nio开销不仅仅是上下文切换开销)。
但现在我看到所有“尖端”服务器都使用异步库(Java nio,epoll,甚至node.js)。这是否意味着async赢了?
答案 0 :(得分:7)
不在我看来。如果两个模型都得到很好的实施(这是一个很大的要求),我认为NIO的概念应该占上风。
计算机的核心是核心。无论你做什么,你都不能比你的核心更多地并行化你的应用程序。即如果你有一台4核机器,你一次只能做4件事(我在这里略过一些细节,但这足以满足这个要求)。
扩展这个想法,如果你有比核心更多的线程,你就浪费了。这种浪费有两种形式。首先是额外线程本身的开销。其次是在线程之间切换所花费的时间。两者都可能很小,但它们都存在。
理想情况下,每个核心都有一个线程,并且每个线程在其核心上以100%的处理速度运行。在理想情况下不会发生任务切换。当然还有操作系统,但如果您使用16核心机器并为操作系统留下2-3个线程,那么剩余的13-14将转向您的应用程序。这些线程可以切换他们在你的应用程序中正在做的事情,比如当他们被IO要求阻止时,但不必在操作系统级别支付这笔费用。将其写入您的应用程序。
在SEDA http://www.eecs.harvard.edu/~mdw/proj/seda/中可以看到这种缩放的一个很好的例子。它显示了比标准的每个请求线程模型更好的负载扩展。
我的个人经历是Netty。我有一个简单的应用程序。我在Tomcat和Netty中都很好地实现了它。然后我加载100次并发请求(我认为超过800)。最终,Tomcat逐渐减速并表现出非常突发/迟滞的行为。虽然Netty的实施只是增加了响应时间,但仍以令人难以置信的整体吞吐量继续。
请注意,这取决于可靠的实施。 NIO随着时间的推移仍在变得越来越好。我们正在学习如何调整我们的服务器操作系统以更好地使用它以及如何实现JVM以更好地利用操作系统功能。我不认为胜利者可以宣布,但我相信NIO将成为最终的赢家,而且它已经做得很好。
答案 1 :(得分:6)
只要有足够的内存,它就会更快。
当连接太多,大多数都是空闲时,NIO可以保存线程,从而节省内存,系统可以处理比每个连接线程模型更多的用户。
CPU不是这里的直接因素。使用NIO,您实际上需要自己实现一个线程模型,这不可能比JVM的线程更快。
在任何一种选择中,记忆都是最终的瓶颈。当负载增加并且使用的内存接近最大值时,GC将非常繁忙,并且系统经常会出现100%CPU的症状。
答案 2 :(得分:4)
前段时间我发现rather interesting presentation提供了一些有关“为什么旧的每个客户端模型更好”的见解。甚至有测量。不过我还是在想。在我看来,这个问题的最佳答案是“它取决于”,因为大多数(如果不是全部)工程决策都是权衡取舍。
答案 3 :(得分:1)
就像那个演示文稿所说的那样 - 速度和可扩展性。
一种情况,每个请求的线程几乎肯定会比任何异步解决方案更快,因为当您拥有相对较少数量的客户端(例如< 100),但每个客户端的数量非常大。例如一个实时应用程序,每个客户端每秒发送/生成500条消息不超过100个。每个请求线程模型肯定比任何异步事件循环解决方案更有效。当有许多请求/客户端时,异步会更好地扩展,因为它不会浪费在许多客户端连接上等待的周期,但是当你没有很少的高容量客户端时,它的效率就会降低。
根据我的看法,Node和Netty的作者都认识到这些框架主要用于解决大容量/多连接可扩展性问题,而不是为较少数量的大容量客户端提供更快的速度。