我想在JS中做一些资源密集型的任务。对于这个问题,我们假设它们是一些繁重的计算,而不是系统访问。现在我想同时运行任务A,B和C,并在完成时执行一些函数D.
async library为此提供了一个很好的支架:
async.parallel([A, B, C], D);
如果我正在做的只是计算,那么它仍将同步运行(除非库将任务放在不同的线程上,我预计不是这种情况)。我该如何让它实际上是平行的?通常由异步代码完成的事情是什么,以阻止调用者(使用NodeJS时)?是开始child process吗?
答案 0 :(得分:36)
如何让它实际上是平行的?
首先,在单节点应用程序中,您不会真正并行运行。节点应用程序在单个线程上运行,并且节点的事件循环一次只处理一个事件。即使在多核盒上运行,也不会在节点应用程序中获得处理的并行性。
也就是说,您可以在多核计算机via forking the code into separate node processes或by spawning child process上处理并行处理。实际上,这允许您创建节点本身的多个实例,并以不同方式与这些进程通信(例如,stdout,进程分支IPC机制)。此外,您可以选择将功能(通过职责)分离到他们自己的节点应用程序/服务器中,并通过RPC调用它。
async 代码通常做什么来阻止调用者(使用NodeJS时)? 是否启动了子进程?强>
它没有开始新的流程。在when async.parallel is used in node.js下方,它正在使用process.nextTick()
。而nextTick()允许您通过将工作推迟到新堆栈来避免阻塞调用者,这样您就可以交错cpu密集型任务等。
长话短说
Node不会让“开箱即用”变得简单,以实现多处理器的并发性。 Node改为为您提供非阻塞设计和利用线程而不共享内存的事件循环。多个线程无法共享数据/内存,因此不需要锁定。节点无锁。一个节点进程利用一个线程,这使得节点既安全又强大。
当您需要在多个进程之间拆分工作时,请使用某种消息传递与其他进程/服务器通信。,例如IPC / RPC。
了解更多信息:
来自What is Node.js的SO的精彩回答......带来了很多善良。
答案 1 :(得分:13)
异步和并行不是一回事。异步意味着您不必等待同步。并行意味着您可以同时执行多项操作。 Node.js只是异步的,但它只有1个线程。它一次只能处理1件事。如果你有一个长时间运行的计算,你应该启动另一个进程,然后让你的node.js进程异步等待结果。
为此,您可以使用child_process.spawn,然后从stdin中读取数据。
http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
var spawn = require('child_process').spawn;
var process2 = spawn('sh', ['./computationProgram', 'parameter'] );
process2.stderr.on('data', function (data) {
//handle error input
});
process2.stdout.on('data', function (data) {
//handle data results
});
答案 2 :(得分:4)
请记住,I / O由Node.js并行化;只有你的JavaScript回调是单线程的。
假设您正在编写服务器,添加产生进程或分支的复杂性的替代方法是简单地构建无状态节点服务器并为每个核心运行实例,或者更好地在其自己的虚拟化微服务器中运行多个实例。使用反向代理或负载均衡器协调传入请求。
您还可以将计算卸载到另一台服务器,可能是MongoDB(使用MapReduce)或Hadoop。
要成为真正的硬核,你可以用C ++编写一个Node插件,并且可以对并行计算代码进行细粒度的控制。无论如何,从C ++加速可能会否定并行化的需要。
您总是可以编写代码来执行最适合数值计算的另一种语言的计算密集型任务,例如:通过REST API公开它们。
最后,您可以使用node-cuda
或类似的东西在GPU上运行代码,具体取决于计算类型(并非所有都可以针对GPU进行优化)。
是的,您可以派生并生成其他进程,但在我看来,节点的主要优点之一是不必担心并行化和线程化,因此完全绕过了大量的复杂性。
答案 3 :(得分:3)
根据您的使用情况,您可以使用类似
的内容task.js 简化界面,让CPU密集型代码在所有核心(node.js和web)上运行
一个例子是
function blocking (exampleArgument) {
// block thread
}
// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);
// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
// do something with result
});
答案 4 :(得分:2)
刚刚遇到parallel.js,但它似乎实际上是使用多核,并且还具有map reduce类型功能。 http://adambom.github.io/parallel.js/