我尝试并行运行多个子进程(.py脚本,使用child_process.exec()),但一次不超过指定的数量(例如,2)。我批量收到未知数量的请求(比如这批请求有3个请求)。我想停止产生过程,直到当前的过程结束。
for (var i = 0; i < requests.length; i++) {
//code that would ideally block execution for a moment
while (active_pids.length == max_threads){
console.log("Waiting for more threads...");
sleep(100)
continue
};
//code that needs to run if threads are available
active_pids.push(i);
cp.exec('python python-test.py '+ requests[i],function(err, stdout){
console.log("Data processed for: " + stdout);
active_pids.shift();
if (err != null){
console.log(err);
}
});
}
我知道虽然循环不起作用,但这是第一次尝试。
我猜这是用
做到这一点的方法setTimeout(someSpawningFunction(){
if (active_pids.length == max_threads){
return
} else {
//spawn process?
}
},100)
但我无法完全理解它。
或者
waitpid(-1)
在if语句中插入for循环代替while循环?但是我现在无法安装waitpid()模块。
是的,我知道阻止执行在JS中被认为非常糟糕,但就我而言,我需要它发生。如果可能的话,我宁愿避免使用外部集群管理器类型库。
感谢您的帮助。
编辑/部分解决方案
丑陋的黑客将使用以下答案:this SO question(execSync())。但这会阻止循环直到最后一个孩子完成。这是我迄今为止的计划,但并不理想。
答案 0 :(得分:4)
async
库的 async.timesLimit
是此处使用的完美工具。它允许您异步运行函数n
次,但在任何给定时间并行运行最多k
个函数调用。
async.timesLimit(requests.length, max_threads, function(i, next){
cp.exec('python python-test.py '+ requests[i], function(err, stdout){
console.log("Data processed for: " + stdout);
if (err != null){
console.log(err);
}
// this task is resolved
next(null, stdout);
});
}, function(err, stdoutArray) {
// this runs after all processes have run; what's next?
});
或者,如果您希望错误致命并停止循环,请致电next(err, stdout)
。
答案 1 :(得分:2)
您可以只维护一个等待运行的外部进程队列,以及一个当前正在运行的计数器的计数器。队列只包含每个进程的对象,该对象具有包含您需要知道要运行的进程所需的数据的属性。您可以将这些对象的数组用于队列。
每当您收到运行外部流程的新请求时,您都会将其添加到队列中,然后启动外部流程,每次启动计数器时都会增加计数器,直到您的计数器达到最大值。
然后,在监视这些外部进程时,无论何时完成,您都会递减计数器,如果等待运行的任务队列不为空,则启动另一个并再次增加计数器。
async
库内置了这种类型的功能(一次运行特定数量的操作),尽管使用队列和计数器实现自己并不困难。关键是你只需要为你的外部流程挂钩即可,这样你就可以维护计数器并启动任何等待的新任务。
没有理由需要使用同步或串行执行或阻止才能在此实现目标。