Node.js NodeJS通过流复制文件的速度非常慢

Node.js NodeJS通过流复制文件的速度非常慢,node.js,performance,file-io,stream,pipe,Node.js,Performance,File Io,Stream,Pipe,我使用VMWare下的SSD上的节点复制文件,但性能非常低。我用来测量实际速度的基准如下: $ hdparm -tT /dev/sda /dev/sda: Timing cached reads: 12004 MB in 1.99 seconds = 6025.64 MB/sec Timing buffered disk reads: 1370 MB in 3.00 seconds = 456.29 MB/sec 但是,以下复制文件的节点代码非常慢,后续运行不会使其更快: var

我使用VMWare下的SSD上的节点复制文件,但性能非常低。我用来测量实际速度的基准如下:

$ hdparm -tT /dev/sda

/dev/sda:
 Timing cached reads:   12004 MB in  1.99 seconds = 6025.64 MB/sec
 Timing buffered disk reads: 1370 MB in  3.00 seconds = 456.29 MB/sec
但是,以下复制文件的节点代码非常慢,后续运行不会使其更快:

var fs  = require("fs");
fs.createReadStream("bigfile").pipe(fs.createWriteStream("tempbigfile"));
其运行方式如下:

$ seq 1 10000000 > bigfile
$ ll bigfile -h
-rw-rw-r-- 1 mustafa mustafa 848M Jun  3 03:30 bigfile
$ time node test.js 

real    0m4.973s
user    0m2.621s
sys     0m7.236s
$ time node test.js 

real    0m5.370s
user    0m2.496s
sys     0m7.190s
$ dd if=/dev/zero bs=8M count=128 | pv | dd of=/dev/null
128+0 records in 174MB/s] [        <=>                                                                                ]
128+0 records out
1073741824 bytes (1.1 GB) copied, 5.78077 s, 186 MB/s
   1GB 0:00:05 [ 177MB/s] [          <=>                                                                              ]
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 5.78131 s, 186 MB/s
$ dd if=/dev/zero bs=8M count=128 |  dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 5.57005 s, 193 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 5.5704 s, 193 MB/s
$ dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 4.61734 s, 233 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 4.62766 s, 232 MB/s
$ dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 4.22107 s, 254 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 4.23231 s, 254 MB/s
$ dd if=/dev/zero bs=8M count=128 | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 5.70124 s, 188 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 5.70144 s, 188 MB/s
$ dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 4.51055 s, 238 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 4.52087 s, 238 MB/s
这里的问题是什么?我如何加快速度?我相信只要调整缓冲区大小,我就可以用C写得更快。让我困惑的是,当我编写简单的几乎等同于pv的程序时,它将stdin传输到stdout,如下所示,速度非常快

process.stdin.pipe(process.stdout);
其运行方式如下:

$ seq 1 10000000 > bigfile
$ ll bigfile -h
-rw-rw-r-- 1 mustafa mustafa 848M Jun  3 03:30 bigfile
$ time node test.js 

real    0m4.973s
user    0m2.621s
sys     0m7.236s
$ time node test.js 

real    0m5.370s
user    0m2.496s
sys     0m7.190s
$ dd if=/dev/zero bs=8M count=128 | pv | dd of=/dev/null
128+0 records in 174MB/s] [        <=>                                                                                ]
128+0 records out
1073741824 bytes (1.1 GB) copied, 5.78077 s, 186 MB/s
   1GB 0:00:05 [ 177MB/s] [          <=>                                                                              ]
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 5.78131 s, 186 MB/s
$ dd if=/dev/zero bs=8M count=128 |  dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 5.57005 s, 193 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 5.5704 s, 193 MB/s
$ dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 4.61734 s, 233 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 4.62766 s, 232 MB/s
$ dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 4.22107 s, 254 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 4.23231 s, 254 MB/s
$ dd if=/dev/zero bs=8M count=128 | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 5.70124 s, 188 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 5.70144 s, 188 MB/s
$ dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 4.51055 s, 238 MB/s
2097152+0 records in
2097152+0 records out
1073741824 bytes (1.1 GB) copied, 4.52087 s, 238 MB/s
$dd if=/dev/zero bs=8M count=128 | pv | dd of=/dev/null
174MB/s中有128+0条记录][]
128+0记录输出
已复制1073741824字节(1.1 GB),5.78077秒,186 MB/s
1GB 0:00:05[177MB/s][]
中的2097152+0记录
2097152+0记录输出
已复制1073741824字节(1.1 GB),5.78131秒,186 MB/s
$dd if=/dev/zero bs=8M count=128 | dd of=/dev/null
中的128+0记录
128+0记录输出
已复制1073741824字节(1.1 GB),5.57005秒,193 MB/s
中的2097152+0记录
2097152+0记录输出
已复制1073741824字节(1.1 GB),5.5704秒,193 MB/s
$dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
中的128+0记录
128+0记录输出
已复制1073741824字节(1.1 GB),4.61734秒,233 MB/s
中的2097152+0记录
2097152+0记录输出
已复制1073741824字节(1.1 GB),4.62766秒,232 MB/s
$dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
中的128+0记录
128+0记录输出
已复制1073741824字节(1.1 GB),4.22107秒,254 MB/s
中的2097152+0记录
2097152+0记录输出
已复制1073741824字节(1.1 GB),4.23231秒,254 MB/s
$dd if=/dev/zero bs=8M count=128 | dd of=/dev/null
中的128+0记录
128+0记录输出
已复制1073741824字节(1.1 GB),5.70124秒,188 MB/s
中的2097152+0记录
2097152+0记录输出
已复制1073741824字节(1.1 GB),5.70144秒,188 MB/s
$dd if=/dev/zero bs=8M count=128 | node test.js | dd of=/dev/null
中的128+0记录
128+0记录输出
已复制1073741824字节(1.1 GB),4.51055秒,238 MB/s
中的2097152+0记录
2097152+0记录输出
已复制1073741824字节(1.1 GB),4.52087秒,238 MB/s

我不知道你的问题的答案,但这可能有助于你调查这个问题

在Node.js中关于流缓冲,它说:

和流都将数据存储在内部数据库中 可使用
writable.writableBuffer
可读。分别为readableBuffer

潜在缓冲的数据量取决于
highWaterMark
选项传递到流的构造函数中。对于正常流
highWaterMark
选项指定总字节数。溪流 在对象模式下运行时,
highWaterMark
指定总数 物体的形状

API的一个关键目标,特别是方法, 将数据缓冲限制在可接受的水平,以便 不同速度的来源和目的地不会压倒 可用内存

因此,您可以使用缓冲区大小来提高速度:

var fs = require('fs');
var path = require('path');
var from = path.normalize(process.argv[2]);
var to = path.normalize(process.argv[3]);

var readOpts = {highWaterMark: Math.pow(2,16)};  // 65536
var writeOpts = {highWaterMark: Math.pow(2,16)}; // 65536  

var source = fs.createReadStream(from, readOpts);
var destiny = fs.createWriteStream(to, writeOpts)

source.pipe(destiny);

不使用节点复制文件。你看,将stdout传输到stdin没有任何开销,我怀疑这是文件的缓冲区大小问题。任何人否决了这一点,都应该再想一想,将其调整到该大小会使其速度几乎提高2倍,这更接近本机speep。谢谢您知道为什么
highWaterMark
不是此处列出的
fs.createWriteStream(路径[,选项])
的选项,以及是否可以调整从api请求返回的可读流的
highWaterMark