首页 > 解决方案 > Node.js 工作线程中的 I/O 性能

问题描述

这是一个使用工作线程的示例,它在本地机器上花费约 600 毫秒来进行同步 I/O:

const fs = require('fs');
const { isMainThread, Worker, parentPort, workerData } = require('worker_threads');

const filename = './foo.txt';

if (isMainThread) {
    (async () => {
        console.time('!');

        await new Promise((resolve, reject) => {
            const worker = new Worker(__filename, { workerData: filename });

            worker.on('message', resolve);
            worker.on('error', reject);
            worker.on('exit', (code) => {
                if (code !== 0)
                    reject(new Error(`Worker stopped with exit code ${code}`));
            });
        });

        console.timeEnd('!');   
    })().catch(console.error);
} else {
    for (let i = 0; i < 100; i++)
        fs.readFileSync(workerData);

    parentPort.postMessage('ok');
}

使用单线程的相同示例需要大约 2 秒的异步 I/O:

const fs = require('fs');

const filename = './foo.txt';

console.time('worker');

(function read(i) {
    if (i < 100) {
        fs.readFile(filename, () => read(++i));
        return;
    }

    console.timeEnd('worker');  
})(0);

显然,同步阻塞操作在这里效率更高。

Node.js工作线程参考状态:

Worker 对于执行 CPU 密集型 JavaScript 操作很有用;不要将它们用于 I/O,因为 Node.js 用于异步执行操作的内置机制已经比 Worker 线程更有效地处理它。

这种说法的依据是什么?

关于 I/O,主线程和工作线程有什么区别?

工人的目的不是不限于非阻塞异步操作吗?

在哪些情况下 I/O 性能在工作线程中可能会降低效率?

标签: javascriptnode.jsmultithreadingworkerworker-thread

解决方案


您在 Node.js 中发现了一个明显的性能问题。

我猜你是在非常大的文件上测试它,因为这是这个问题影响最大的地方。

问题是在一个操作(一个系统调用)中readFileSync读取整个文件,同时读取 512Kb 的块。readreadFile

我已经提交了一个 PR 来解决这个问题,这里是讨论: https ://github.com/nodejs/node/pull/41436

有了这个 PRreadFile就会变得稍微快一点,然后readFileSync 没有创建新线程的开销。如果添加新线程创建,则差异更加明显。

Node.js 是为异步 IO 而设计的,这是最有效的。


推荐阅读