限制CPU NODE.JS操作以允许处理新调用

限制CPU NODE.JS操作以允许处理新调用,node.js,asynchronous,express,fork,Node.js,Asynchronous,Express,Fork,我有一个expressJS应用程序,它接受一个导致执行1K到50K fs.link()操作的请求。(甚至可能达到500公里) 发生这种情况时,请求(帖子)不会被挂起。我立即发出一个res.send()命令,使客户感到高兴 但是服务器随后会“分叉”下面的作业,这需要去做所有的fs.links(),这些都是异步发生的,但是工作量(CPU、磁盘等)意味着ExpressJS服务在这段时间内对新请求的响应不是很快 是否有一些简单的方法(除了childProcess)来模拟执行这些文件链接的低优先级线程的分

我有一个expressJS应用程序,它接受一个导致执行1K到50K fs.link()操作的请求。(甚至可能达到500公里)

发生这种情况时,请求(帖子)不会被挂起。我立即发出一个res.send()命令,使客户感到高兴

但是服务器随后会“分叉”下面的作业,这需要去做所有的fs.links(),这些都是异步发生的,但是工作量(CPU、磁盘等)意味着ExpressJS服务在这段时间内对新请求的响应不是很快

是否有一些简单的方法(除了childProcess)来模拟执行这些文件链接的低优先级线程的分叉



您可以使用该模块,它有助于将CPU密集型任务旋转到其他线程上。或者,您可以滥用
集群
,但这确实是一个错误的工具。(集群模块更适合扩展web服务,而不是执行密集型任务。)

您可以尝试使用async.eachLimit而不是async.each。通过这种方式,您可以控制在expressJS进程之前处理的迭代次数。

我添加了链接任务的代码示例。(a) 我不确定这是CPU限制问题还是I/O问题(从理论上讲,链接文件似乎更像是I/O问题)。workther线程会很有趣,但他们说您需要一个工作节点gyp,而我已经几个月没能让它工作了(问题仍然悬而未决)。简单点怎么样。例如,每1000个文件,调用一个使该节点休眠的超时例程“线程”,然后稍后恢复链接过程。啊,我明白了。是的,通过在每个文件上调用它,您可能滥用了
async.each
。(
async.eachLimit
可能会有所帮助,但您仍将生成大量事件。)这使得您的任务比需要的CPU密集度更高。我建议您分析一下,用async调用
fs.link
(而不是一次调用全部)的开销,然后尝试将文件数组拆分为1000个文件块。您应该能够避免垃圾邮件事件(因为500K文件无论如何只会产生500个事件),并且仍然让其他事件在两者之间运行。我将尝试async.eachLimit()以查看它是否有帮助。我真正想做的就是等效于thread.yield(),这样就可以处理新的ExpressJS请求(进度轮询)。如果这意味着原始请求被强制暂停,或者被限制到50%,则可以。如何强制“线程”停止。也就是说,我可以在.each循环中插入process.nextTick()吗?它会有帮助吗?怎么把它放进去?没有办法像那样“让线屈服”。函数始终同步执行到完成。相反,您需要将较大的任务分解为较小的工作单元。这是您以前所做的,但是您将其分解为数十万个任务,这可能会使您的事件循环过载(而任务创建本身的计算成本很高)。试着创建一个数量较少的任务,每个任务做更多的工作,并调整这些任务的数量,直到您获得所需的性能。亨利,也许我不是在解释我自己。但我看了这篇文章:,对我来说,它基本上是说process.nextTick()是C.S.表示“屈服”这个线程的经典技巧。它暂停当前“线程”执行(尽管是在当前调用堆栈完成之后),将回调放在事件队列上,并让所有其他等待的“线程”执行。这似乎是解决这个问题的一种方法。我会回来报到的。
Job.prototype.runJob = function (next) {
    var self = this;
    var max = this.files.length;
    var count = 0;
    async.each(this.files,
        function (file, step) {
            var src = path.join(self.sourcePath, file.path);
            var base = path.basename(src);
            var dest = path.join(self.root, base);
            fs.link(src, dest, function (err) {
                if (err) {
//                    logger.addLog('warn', "fs.link failed for file: %s", err.message, { file: src });
                    self.filesMissingList.push(src);
                    self.errors = true;
                    self.filesMissing++;
                } else {
                    self.filesFound++;
                }
                self.batch.update({ tilesCount: ++count, tilesMax: max, done: false });
                step(null);
            });
        },
        function (err) {
            self.batch.update({ tilesCount: count, tilesMax: max, done: true });
            next(null, "FalconView Linking of: " + self.type + " run completed");
        });
}