我正在尝试以高性能的方式解决 nodejs 中的以下场景。
- 我有一个价值 100Mb 的 jsons 需要处理,处理每个条目的时间函数约为
O(sweet_jesus(n))
. 实时每个条目大约需要 4-5 秒。 - 我可以完全单独处理每个条目(总共大约 900 个条目)的唯一一线希望,它们是不相关的。
worker_threads
我的第一选择是选择node-worker-threads-pool
:
import fs from 'fs';
import path from 'path';
import _ from 'lodash';
import moment from 'moment';
import workerPool from 'node-worker-threads-pool';
function generateShortEvaluationsByWorkers(){
const pool = new workerPool.StaticPool({
size: 10,
task: path.resolve('src/simulator/evaluationGenerator.js')
});
let simulationEvaluations = [];
const promises = [];
fs.readdirSync(path.resolve(`results/companies`)).forEach(file => {
const rawData = fs.readFileSync(path.resolve(`results/companies/${file}`));
const company = JSON.parse(rawData);
console.log(new Date(), ": company parsed, sending it for processing:", file);
promises.push(pool.exec(company).then(result=>{
simulationEvaluations.push(result);
}));
});
Promise.all(promises).then(()=>{
fs.writeFileSync(
path.resolve(`results/bundles/simulationEvaluations.json`), JSON.stringify(simulationEvaluations, null, 2)
);
pool.destroy();
})
}
上面的代码运行得很漂亮,它表明 I/O - 读取所有文件并将其提供给池 - 大约需要 5-6 秒......
但之后与运行整个文件相比绝对没有任何区别一个线程。日志确实显示单个文件的处理不再像以前那样按顺序发生,所以我猜后台发生了一些线程,但总时间并没有改变一点。无论哪种方式都需要大约一个小时。此外,我的具有 6 个内核(12 个逻辑)的超线程 Intel 8750 显示 86% 的利用率用于节点进程。所以我所谓的 10 个独立线程甚至无法利用一个完整的核心。-编辑:我是个智障,我写错了时间确实有很大的不同......
在此之后,我将线程池大小增加到 100,并将文件数量减少到 100。这就是奇怪的事情开始发生的地方。首先,我所有的 CPU 内核都运行了 brrrr,并且我的笔记本电脑正确地从桌子上消失了,正如人们所期望的那样。操作系统提供零响应,一切都是幻灯片。前 20 个左右的文件在同一秒内得到处理,之后单个文件的处理时间约为 3 秒(彼此整齐地排列,一个消息在另一个消息之后 3-5 秒)。最后 10 个左右的文件在同一秒内再次得到处理。
- 为什么 10 个线程与 1 个线程相比没有区别?
- 我不应该看到要在集群中处理的文件,其中集群大小与逻辑核心的数量相当,而不是一个接一个的时间戳?
- 有没有办法“离开”一个核心来处理其他事情,而计算仍然和所有其他核心一起去海王星?
编辑:我不会删除这个,也许有人会从中学习:) 所以回答我自己的问题:
- 它确实如此,我无法测量,无法写入,也无法读取我的 CPU 计量表……完全是我的错
- 这个我仍然没有完全理解,但是经过几次运行后,我怀疑当您启动整个对接负载的线程时,您会因为启动它们的压力而使整个系统挂起这么多,直到它能够吐出第一个日志,它已经完成了一堆计算。
- 是的,这也很明显,不要使用太多线程,以免线程管理本身会使操作系统陷入困境。
最后,顺便说一句,我用 11 个线程获得了最好的结果。