如果所有的node.js工作线程都忙碌,会发生什么?

4
我尝试理解node.js的工作原理,虽然我已经阅读了这篇文章:When is the thread pool used?,但我不确定如果所有工作线程都忙碌并且另一个异步I/O操作准备好执行会发生什么。
如果我正确理解了这篇文章http://www.future-processing.pl/blog/on-problems-with-threads-in-node-js/,那么事件循环会被阻塞,直到有一个工作线程空闲来处理额外的I/O操作。这意味着如果五个用户同时尝试访问一个网页(比如他们的个人资料页面需要进行数据库查询),第五个用户将被阻塞,直到第一个数据库查询完成并且该工作线程再次空闲为止?

请记住,您将需要检查数据库库如何执行其I/O操作。它可能会或可能不会使用Node.js线程池。 - jfriend00
如果您提供更完整的示例以及您的想法,将对我有所帮助。例如,您正在运行哪种类型的Web服务器?简要说明一下您的多线程应用程序架构,并介绍它在什么上下文中使用。 - Mike Robinson
我并没有特定的想法;我只是很好奇。我知道Paypal正在使用Node,并且我认为每个数据库查询都将在worker线程中进行,以便不会阻塞主事件循环。 - Daniel
2个回答

4

一般而言,I/O操作不会阻塞事件循环(有一些例外情况,比如crypto模块和fs.*Sync()方法),特别是在网络I/O的情况下,libuv线程池根本就不会被使用(仅用于dns(目前)和fs操作等其他操作)。

如果你的数据库驱动程序是作为node.js插件以C++编写的,那么它可能会阻塞事件循环(正在执行同步操作)或者可能正在使用libuv线程池。但是,如果数据库驱动程序只是用JavaScript编写的,则通常使用某种形式的网络I/O,正如之前提到的那样,这种方式不会阻塞任何内容,也不会使用libuv线程池。

因此,对于你的示例,根据数据库驱动程序的实现方式,所有5个用户都可以同时服务。例如,MySQL协议层每个连接一次只支持一个未完成的查询。因此,大多数node.js的MySQL驱动程序将排队等待其他查询完成后再执行其他查询。但是,完全可以通过MySQL驱动程序内部维护某种类型的连接池来实现更高的并发性。

然而,如果这5个请求中的每个请求都导致从磁盘读取数据,那么由于libuv线程池的默认大小,第5个请求可能需要等待其中一个其他4个fs请求完成。这并不意味着事件循环本身被阻塞,因为它仍然可以处理新的传入请求和其他操作,但第5个客户端只需稍等片刻。


谢谢你的回答。我在最初的问题中应该更加明确,但你几乎回答了我所有不确定的问题。我指的是异步操作(例如通过mongoose进行的mongoDB查询)。那么,在工作线程中执行的操作是否有任何类型的队列? - Daniel
根据快速搜索,似乎mongodb也有类似的限制——每个连接只能有一个未完成的查询。然而,mongoose模块内部支持连接池(poolSize)。对于任何操作都有一个队列,这些操作将被发送到libuv线程池。正如我在答案中提到的那样,这包括像DNS查询(目前)和文件系统操作等内容。 - mscdex

1

在工作线程中执行的操作是否有某种队列机制?

有。libuv 管理着这个队列。如果所有工作线程都被占用,那么发送到工作池的新异步请求将无法进展。请注意,“异步 FS 请求”仍然必须在某个地方完成,并且会阻塞正在处理它的工作线程,直到完成为止。


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