Node.Js Windows 中的线程池
Node.Js Threadpool in Windows
所以我的理解是,任何阻塞的文件系统操作(例如fs.readFileSync)最终都会委托给线程池中的线程之一,以保持事件循环空闲。现在,我 运行 来自 windows 的应用程序和我正在使用的命令 set UV_THREADPOOL_SIZE=4 & node index.js
下面是我的示例代码,
const start = new Date().getTime();
readFile();
readFile();
readFile();
readFile();
readFile();
function readFile() {
fs.readFileSync('./content/1.txt');
const end = new Date().getTime();
console.log('Time took: ', (end - start) / 1000);
}
现在无论我将线程池大小设置为一个还是四个,执行时间都几乎相同。仅供参考,我的 PC 中有 两个 CPU 核心 。因此,我的期望是,如果我在读取文件的 5 个函数调用中将线程池大小设置为 4(或让默认设置起作用),那么说前四个需要 x 秒(我知道这不是确切的时间两者都调用但会非常接近),然后是最后一个 (x+n),其中 x 和 n 是随机数并表示以秒为单位的时间差。
但这并没有发生。无论线程池调用的数量如何,都需要花费相同的时间来完成并且一个接一个地完成。
所以,看来我对 node.js 线程池如何工作的理解是不正确的。任何帮助,将不胜感激。谢谢。
第一个问题是您正在使用 fs.readFileSync()
。这意味着您的文件操作一次只会被请求一个。在第一个完成之前,第二个不会开始。这与线程池无关。这是因为您正在使用 readFile()
的阻塞同步版本。 JS 解释器将被阻塞,直到第一个 fs.readFileSync()
完成,第二个只在第一个完成后才开始,依此类推。因此,因此,在这种情况下,有多少线程为文件系统提供服务并不重要。
如果你想在文件操作中使用多个线程,你需要使用像fs.readFile()
这样的异步文件操作,这样你就可以同时进行多个文件操作,从而拥有更多有机会使用多个线程。
另外,同一个磁盘上的文件操作不像其他类型的操作那样具有多个 threads/CPUs 的可扩展性,因为 read/write 磁头一次只能在一个地方,所以即使您确实更改了代码以成功使用多个线程或 CPU 由于 read/write 头位置的序列化,您无法在同一驱动器上获得完全并行的文件访问。
下面是一个使用异步 fs.readFile()
的测试示例:
const start = new Date().getTime();
let cntr = 0;
readFile(0);
readFile(1);
readFile(2);
readFile(3);
readFile(4);
function readFile(i) {
fs.readFile('./content/1.txt', function(err, data) {
if (err) {
console.log(err);
return;
}
const end = new Date().getTime();
console.log(`Time took: ${i} ${(end - start) / 1000}`)
if (++cntr === 5) {
console.log(`All Done. Total time: ${(end - start) / 1000)}`;
}
});
}
如果您每次调用 readFile()
时读取不同的文件(不在 OS 文件缓存中),此测试可能会更有意义。因为它是 2-5 个请求,可能只是从 OS 文件缓存中的内存中获取数据,而不是实际访问磁盘。
所以我的理解是,任何阻塞的文件系统操作(例如fs.readFileSync)最终都会委托给线程池中的线程之一,以保持事件循环空闲。现在,我 运行 来自 windows 的应用程序和我正在使用的命令 set UV_THREADPOOL_SIZE=4 & node index.js
下面是我的示例代码,
const start = new Date().getTime();
readFile();
readFile();
readFile();
readFile();
readFile();
function readFile() {
fs.readFileSync('./content/1.txt');
const end = new Date().getTime();
console.log('Time took: ', (end - start) / 1000);
}
现在无论我将线程池大小设置为一个还是四个,执行时间都几乎相同。仅供参考,我的 PC 中有 两个 CPU 核心 。因此,我的期望是,如果我在读取文件的 5 个函数调用中将线程池大小设置为 4(或让默认设置起作用),那么说前四个需要 x 秒(我知道这不是确切的时间两者都调用但会非常接近),然后是最后一个 (x+n),其中 x 和 n 是随机数并表示以秒为单位的时间差。
但这并没有发生。无论线程池调用的数量如何,都需要花费相同的时间来完成并且一个接一个地完成。
所以,看来我对 node.js 线程池如何工作的理解是不正确的。任何帮助,将不胜感激。谢谢。
第一个问题是您正在使用 fs.readFileSync()
。这意味着您的文件操作一次只会被请求一个。在第一个完成之前,第二个不会开始。这与线程池无关。这是因为您正在使用 readFile()
的阻塞同步版本。 JS 解释器将被阻塞,直到第一个 fs.readFileSync()
完成,第二个只在第一个完成后才开始,依此类推。因此,因此,在这种情况下,有多少线程为文件系统提供服务并不重要。
如果你想在文件操作中使用多个线程,你需要使用像fs.readFile()
这样的异步文件操作,这样你就可以同时进行多个文件操作,从而拥有更多有机会使用多个线程。
另外,同一个磁盘上的文件操作不像其他类型的操作那样具有多个 threads/CPUs 的可扩展性,因为 read/write 磁头一次只能在一个地方,所以即使您确实更改了代码以成功使用多个线程或 CPU 由于 read/write 头位置的序列化,您无法在同一驱动器上获得完全并行的文件访问。
下面是一个使用异步 fs.readFile()
的测试示例:
const start = new Date().getTime();
let cntr = 0;
readFile(0);
readFile(1);
readFile(2);
readFile(3);
readFile(4);
function readFile(i) {
fs.readFile('./content/1.txt', function(err, data) {
if (err) {
console.log(err);
return;
}
const end = new Date().getTime();
console.log(`Time took: ${i} ${(end - start) / 1000}`)
if (++cntr === 5) {
console.log(`All Done. Total time: ${(end - start) / 1000)}`;
}
});
}
如果您每次调用 readFile()
时读取不同的文件(不在 OS 文件缓存中),此测试可能会更有意义。因为它是 2-5 个请求,可能只是从 OS 文件缓存中的内存中获取数据,而不是实际访问磁盘。