这篇文章虽然有些老,但回答还是很有价值的。首先我们来说一下每种模型的工作方式。
在线程模型中,请求进入处理程序后,处理程序会生成一个新的操作系统线程来处理该请求,并且所有与该请求相关的工作都在该线程中进行,直到响应被发送并结束该线程。此模型支持与服务器可以生成的线程数量相同的并发请求数量(但线程可能比较重)。
在异步模型中,请求也是进入处理程序,但不会创建线程来处理它,而是将连接添加到所谓的事件循环中。事件循环监听连接上的数据/状态变化,并在每次“某事”发生时触发回调。一旦连接被添加到事件循环中,处理程序立即开始监听新连接以添加。这允许您同时拥有许多(有时为100K)并发连接。
是否有任何功能/技术无法在异步方法中使用(或者表现得不好/不如预期)?
当你进行数字计算时,异步(或“事件驱动”)系统的架构非常适合传递数据,但不适合处理数据。它可以处理数千个并发操作,但由于它仅在一个操作系统线程上运行,所以触发的回调需要尽可能少地执行操作以获得最大吞吐量。这是因为如果你的其中一个回调执行了需要5秒钟的数字计算,整个服务器将被冻结5秒钟,直到该操作完成。思路是获取数据,将其发送到目标位置(数据库、API等),并通过最小的处理来发送响应。
异步对于网络I/O非常好:在多个源/目标之间传递数据(还包括用户界面,但超出了本篇文章的范围)。
“什么情况会导致异步方法的性能比基于线程/进程的方法更差?这些情况是常见还是罕见,差异有多大?”
参考上文,但任何时候,如果你的 CPU 工作比网络 I/O 更多,你应该切换到线程模型。然而,有一些架构的变通方法……例如,你可以拥有一个异步应用程序,并且每次需要进行实际工作时,都将任务发送到工作者队列。然而,如果每个请求都需要 CPU 处理,那么这种架构就过度了,你最好使用线程化服务器。
在比较两者时,我还应该考虑其他因素吗?请记住,我主要关注基于线程/进程和异步的方法,而不是任何特定的服务器软件使用的方法。这些问题可能会包括管理/调试的难度、安全问题等。
与线程相比,异步编程
通常 更加复杂。尽管如此,如果你不是自己进行编程(即你在nginx和apache之间进行选择),那么我通常建议你选择异步(nginx),因为这样你通常能够从服务器中挤出更多的性能。我总是支持在堆栈中使用尽可能多的异步操作。
如果您正在编写一个应用程序并尝试决定是否使用线程或异步模型,那么您需要考虑开发人员的时间。除非您使用的是具有事件循环的绿色线程语言(如scheme),否则请期望会因为异常错误导致整个应用程序崩溃而感到非常困扰,并且通常需要掌握CPS/为所有内容使用回调函数。 Futures/promises是您的好朋友,但只是一种治标不治本的方法,使异步变得更加美好。
简而言之
如果您在服务器上使用异步,可以比线程模型实现更多并发操作,如果您只是进行网络IO而没有其他操作。
如果您要进行任何类型的数字计算,请使用线程应用程序服务器或者使用带有后台排队系统的异步应用。
除非您的语言支持其上的“假”线程(即绿色线程),否则异步编程要困难得多。一旦您克服了最初的障碍,通常情况下就没问题了。如果没有绿色线程,请使用promises。
如果在你的技术栈中(apache vs nginx)可以选择线程和异步组件,并且它们提供
完全相同的功能,稍微偏向于异步。但不要仅仅因为你认为它会使一切变得快20倍而选择它。