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
或进行伪造setImmediate
或process.nextTick
暂停您的工作并在以后的循环中继续进行,以完成其他过程(但不建议这样做)。
请注意,如果您使用javascript编写长时间运行/阻止的代码,则可能是在犯错误。其他语言将更有效地执行。
TA贡献1840条经验 获得超5个赞
这种误解仅仅是抢先式多任务处理与协作式多任务处理之间的区别...
睡眠会关闭整个狂欢节,因为所有游乐设施实际上只有一条路线,而您关上了大门。将其视为“ JS解释器和其他一些东西”,而忽略线程...对于您来说,只有一个线程,...
...所以不要阻止它。
- 3 回答
- 0 关注
- 1194 浏览
添加回答
举报