为了账号安全,请及时绑定邮箱和手机立即绑定

什么时候使用线程池?

什么时候使用线程池?

忽然笑 2019-10-14 14:20:42
因此,我对Node.js的工作方式有所了解:它具有一个侦听器线程,该线程接收事件,然后将其委托给工作池。工作线程在完成工作后会通知侦听器,然后侦听器将响应返回给调用者。我的问题是:如果我在Node.js中建立一个HTTP服务器,并在我的一个路由路径事件(例如“ / test / sleep”)中调用sleep,则整个系统将停止。甚至是单个侦听器线程。但是我的理解是这段代码正在工作池中发生。现在,相比之下,当我使用Mongoose与MongoDB交谈时,数据库读取是一项昂贵的I / O操作。Node似乎能够将工作委托给线程并在完成时接收回调。从数据库加载所需的时间似乎不会阻塞系统。Node.js如何决定使用线程池线程还是侦听器线程?为什么我不能编写仅休眠和阻塞线程池线程的事件代码?
查看完整描述

3 回答

?
智慧大石

TA贡献1946条经验 获得超3个赞

您对节点如何工作的理解是不正确的……但这是一个常见的误解,因为这种情况的实际情况实际上相当复杂,并且通常归结为诸如“ node is single threaded”之类的小词,过分简化了事情。

目前,我们将忽略通过集群和webworker-threads进行的显式多处理/多线程,而仅讨论典型的非线程节点。

节点在单个事件循环中运行。它是单线程的,您只能获得一个线程。您编写的所有JavaScript都会在此循环中执行,并且如果该代码中发生了阻塞操作,则它将阻塞整个循环,直到完成为止,否则将什么也不会发生。这是您经常听到的节点的典型单线程性质。但是,这还不是全部。

通常使用C / C ++编写的某些功能和模块支持异步I / O。当您调用这些函数和方法时,它们在内部管理将调用传递给工作线程。例如,当您使用该fs模块请求文件时,该fs模块将该调用传递给工作线程,该工作线程等待其响应,然后将其呈现回事件循环,该循环在没有它的情况下一直在进行与此同时。所有这些都是从您(节点开发人员)那里抽象出来的,其中一些是通过使用libuv从模块开发商那里抽象出来的。

正如Denis Dollfus在评论中指出的(从此答案到类似的问题),libuv用于实现异步I / O的策略并不总是线程池,特别是在http模块的情况下,似乎是另一种策略目前使用。对于我们这里的目的,最重要的是要注意如何实现异步上下文(通过使用libuv),并且libuv维护的线程池是该库提供的实现异步的多种策略之一。


在一篇非常相关的切线上,这篇出色的文章对节点如何实现异步性以及一些相关的潜在问题以及如何处理这些问题进行了更深入的分析。它的大部分内容是在我上面写的内容基础上扩展的,但是另外指出:

  • 您包含在项目中的任何使用本机C ++和libuv的外部模块都可能使用线程池(请考虑:数据库访问)

  • libuv的默认线程池大小为4,并使用队列来管理对线程池的访问-结果是,如果您同时有5个长时间运行的数据库查询都在运行,则其中一个(以及任何其他异步查询)依赖于线程池的操作)将等待查询结束,甚至无法开始

  • 您可以通过UV_THREADPOOL_SIZE环境变量增加线程池的大小来缓解这种情况,只要您在需要并创建线程池之前就这样做即可:process.env.UV_THREADPOOL_SIZE = 10;


如果要在节点中使用传统的多处理或多线程,则可以通过内置cluster模块或上述其他各种模块来获取webworker-threads,也可以通过实现某种方式将工作分块并手动使用setTimeout或进行伪造setImmediateprocess.nextTick暂停您的工作并在以后的循环中继续进行,以完成其他过程(但不建议这样做)。

请注意,如果您使用javascript编写长时间运行/阻止的代码,则可能是在犯错误。其他语言将更有效地执行。


查看完整回答
反对 回复 2019-10-14
?
慕斯709654

TA贡献1840条经验 获得超5个赞

这种误解仅仅是抢先式多任务处理与协作式多任务处理之间的区别...

睡眠会关闭整个狂欢节,因为所有游乐设施实际上只有一条路线,而您关上了大门。将其视为“ JS解释器和其他一些东西”,而忽略线程...对于您来说,只有一个线程,...

...所以不要阻止它。


查看完整回答
反对 回复 2019-10-14
  • 3 回答
  • 0 关注
  • 1155 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信