我尝试使用Node.js将大文件(500 MByte)写入磁盘。 我发现,虽然前几个文件可以在几秒钟内完成写入(通常为3至5秒),但从第10个文件开始,速度趋于变慢(而且无法恢复)。
设置包括一个通过TCP/IP套接字接受文件并将它们传输到磁盘的服务器:
var fs = require('fs'),
net = require('net'),
path = require('path');
var counter = 0;
net.createServer(function (socket) {
console.time('received');
console.time('written');
counter++;
var filename = path.join(__dirname, 'temp' + counter + '.tmp');
var file = fs.createWriteStream(filename, { encoding: 'utf8' });
socket.pipe(file);
socket.once('end', function () {
console.timeEnd('written');
});
file.once('finish', function () {
console.timeEnd('received');
});
}).listen(3000);
我通过以下方式使用nc
从终端发送数据:
$ while [ true ]; do `cat input.tmp | nc localhost 3000`; done
运行中
$ time cat input.tmp > /dev/null
研究表明,猫咪总是在同一时间读取文件。如果我将Node.js脚本的输出路径替换为/dev/null
,写入也总是在同一时间发生。
因此,问题显然与实际写入磁盘有关。
起初我以为这可能是并发读写的问题,但即使我运行以下命令,问题仍然存在:
$ while [ true ]; do `cat input.tmp | nc localhost 3000; sleep 5`; done
如果我使用比之前更大的文件(两倍大,即1GB),运行相同的测试,则需要的时间减少了一半,直到写入变慢。
更新
我已经修改了我的Node.js应用程序,将所有内容都写入一个单独的文件中,并不断追加...服务器现在如下:
var fs = require('fs'),
net = require('net'),
path = require('path');
var filename = path.join(__dirname, 'temp.tmp');
var file = fs.createWriteStream(filename, { encoding: 'utf8' });
net.createServer(function (socket) {
console.time('received');
console.time('written');
socket.pipe(file, { end: false });
socket.once('end', function () {
console.timeEnd('written');
});
}).listen(3000);
现在问题已经解决了,显然这与连续写入多个文件有关。至少我没有看到自己同时写入多个文件的地方(难道我有吗?),所以我想不出为什么会发生这种情况。特别是使用
sleep 5
应该确保操作系统已经将所有内容写入磁盘。更新2: 我最初使用的是Node.js 0.10.32版本。当我切换到0.11.13版本时,效果并没有完全消失,但是发生的时间要晚得多。在最初的设置中,问题在大约10个周期后出现,在Node.js 0.11.13中最早在第30个周期发生。
您有什么想法可以解释这种行为吗?
pipe
应该能够很好地清理,而对于其他情况,我使用once
。 - Golo Roden