【问题标题】:NodeJS batch multi processing - child processes in a pool (or multithreading)NodeJS 批处理多处理 - 池中的子进程(或多线程)
【发布时间】:2014-11-12 17:46:24
【问题描述】:

NodeJS 批处理多 threading 处理 - 池中的子进程。

我知道子进程是进程,而不是线程。我使用了错误的语义,因为当您谈到“多线程”时,大多数人都知道您的意图。所以我会保留在标题中。


想象一个场景,您使用单个自定义函数或模块不断地有多个相似且复杂的事情要做。使用所有可用的内核/线程(例如 8/16)很有意义,这就是 child_process.fork() 的用途。

理想情况下,您将需要多个同时工作的工作人员并向/从一个控制器发送/回调消息。

node-cpoolfork-poolchild-pool 是一些可以做到这一点的模块,但它们看起来很旧/未维护/不受欢迎。

有很多类似的模块,但这些似乎是最相关的。它们的共同点是几个提交,几乎没有加星标,几乎没有分叉和放弃。

通常情况下,当我无法为一项似乎在各方面都有意义的任务找到一些东西时,我错过了一种更好的方法。因此我的问题。

如何为我的自定义模块创建一个托管的、排队的、多线程并行池fork()s,以完成一些 CPU 密集型工作?

TAGGwebworker-threads 这样的多线程模块并不相同,因为它们不支持完整的模块(带有二进制编译的组件)。


附言

我现在正在使用fork-pool,它似乎完全符合我的要求,但有一些怪癖,但我不敢相信这样一个未知且不受欢迎的模块将是这里唯一可行的选择。

【问题讨论】:

  • child_process.fork() 创建一个进程而不是一个线程。为每个 CPU 密集型任务分叉一个进程似乎并不正确。 node.js(无需第三方原生模块的帮助)为 IO 密集型应用程序提供单线程环境。您可能可以编写一个多语言应用程序并使用 message-queue 将 CPU 密集型任务卸载到多线程环境。
  • 抱歉,我没有正确处理问题中的语义。我知道fork() 创建了一个流程。事实上,进程线程都在那些“每核线程”硬件通道之一中独立地执行代码。假设我知道我在做什么并且运行 8 个进程就可以了。我从未听过有人抱怨某个软件的运行速度是原来的 2 倍。 Node 以 child_process 的形式为需要它的人提供了一个多线程工具集。

标签: multithreading node.js child-process fork


【解决方案1】:

我建议使用Redis 之类的东西作为您的队列。 Here's a tutorial 使用 Redis 和 Kue 在 Node 中创建消息总线。这将很好地扩展,并允许您拥有多个进程、线程,甚至是机器生产和消费队列中的项目。

【讨论】:

  • 听起来很有趣,点赞。但这看起来也有点像“太多的工作和依赖”。我只想汇集一些进程。那不应该需要太多代码和太多依赖项。我现在正在使用fork-pool,这似乎完全符合我的要求,但我不敢相信这样一个未知且不受欢迎的模块将是这里唯一可行的选择。
【解决方案2】:

Web Workers 标准为 JavaScript 定义了一种使用多线程的方法,并且可以并行执行比单个线程所能管理的更多的工作。

NodeJS 有多种实现方式,包括 webworker-threads NPM 模块。

使用fork 会走上一条多进程路径,通常更难协调。 NodeJS Cluster 系统试图减轻这里的许多摩擦,但远非理想。

【讨论】:

  • 哦,我忘记了 Web Workers。这是一个很好的解决方案。
  • 谢谢,但我在问题的最后部分提到了这些。它们涵盖了仅适用于纯可评估 (eval()) javascript 的实现。不能以这种方式使用具有二进制组件的模块(最有效的模块,如解析器 (xml-expat))。 Javascript线程太有限了。 Fork() 是在某些(这种)情况下需要的。它只是增加了 30ms 的执行时间延迟和每个进程 10MB 的内存使用,开发人员可能有充分的理由选择。
【解决方案3】:

我想提供一个选项,它不能完全回答您的问题,但在您可以灵活选择技术的情况下可能会有用。

如果可以将工作卸载到 .NET 环境(C#、F#、IronPython、PowerShell 等),您可能会对 Edge.js 项目感兴趣。

通过这种方式,您可以将 Node 用于 IO 密集型工作,并将计算密集型工作委托给 .NET 运行时托管在同一进程中。 Edge.js 提供与 .NET 代码的高效互操作性,允许利用 .NET 任务并行库和其他功能,而无需产生额外进程的开销。


每当您制作混合应用时,都会产生维护和技术成本。仔细评估您获得的收益,并确保根据您的项目优先级而付出的代价是值得的。

Node.js 不太适合执行阻塞、受 CPU 限制的工作负载。 node.js 的显着设计特点是其单线程、基于事件循环的架构。

Node.js 应用程序通常通过将处理委派给外部进程或服务来处理受 CPU 限制的工作负载。这涉及跨越进程边界并产生额外的延迟。 (more)

在没有充分理由的情况下引入复杂性是愚蠢的。如果 Node.js 可以自己处理任务,那么添加对 .NET 的依赖可能是矫枉过正。但是,有很多任务when it could be valuable。成为一名优秀的工程师需要一些思考。

【讨论】:

  • 这太夸张了。建议 .NET 作为使用某种队列的替代方案是愚蠢的,尤其是因为您仍然需要一个队列来将消息传递到 .NET 或从 .NET 传递消息。此外,它们可能在 OSX 或 Linux 上运行,使 .NET 成为更糟糕的建议。
  • @Jessie:总的来说,我强烈反对,但我同意在特定情况下这可能是矫枉过正。这取决于许多因素,包括任务的计算密集程度。有一大类问题将从这种方法中受益。另外,为什么 Linux/OSX 会成为问题?
  • 我同意这取决于其他因素。至于 Linux/OSX 支持,C#、F#、PowerShell 等。在 Windows 以外的平台上,所有这些都没有得到很好的支持。 Java、C、C++ 等可能是跨平台开发的更好选择。
  • “Silly”说得客气一点。就像引入 Java (JVM) 或 Haskell 一样,除非它们提供 NodeJS 本身无法做到的东西,否则它们会很荒谬。即便如此,如果 Java 或 Haskell 提供更好的工具,我还是提倡用它们编写解决方案,而不是将两个平台融合在一起。
  • 这是一个有价值的选择,所以我赞成这个答案。但是,在我的特殊情况下,我对汇集 进程 很感兴趣,因为它们可以是任何东西。任何二进制组件(C++ 甚至程序集)都可以包装到一个模块中。如果它们是独立的二进制文件,则可以将它们包装在 spawn() 而不是 fork() 中,尽管在我的特定情况下,我希望使用已编译的二进制组件对某些节点模块进行多处理。 (另外,我在 Linux 上)
【解决方案4】:

我最近遇到了从单个 node.js 进程创建的分叉池的问题,并提出了我自己的解决方案来解决该问题。我终于设法将解决方案导出到它自己的 npm 模块,您可以在此处查看:

https://www.npmjs.com/package/forkpool

您可以创建一个池来管理所有分叉,也可以创建多个池来管理隔离的工作批次。例如,我的一个应用程序有两个池 - 一个用于管理与图像处理相关的分支,另一个用于视频处理。由于视频处理比图像处理更密集,因此视频处理池的大小为 2,而图像处理池的大小在 8 核机器上为 4。

我希望随着时间的推移不断改进此模块,因此请随时在 Github 存储库上提出问题或增强请求:

https://github.com/manthanhd/forkpool

【讨论】:

    猜你喜欢
    • 2022-11-30
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 2012-11-12
    • 2022-01-08
    • 2012-03-31
    相关资源
    最近更新 更多