这是我的 nodejs 实现,结果和预期的差不多:
小文件比分叉的 grep 运行得更快(文件最多 2-3k 短行),
大文件运行速度较慢。文件越大,差异越大。
(也许正则表达式越复杂,差异越小——见
下面。)
我使用自己的qfgets 包快速
一次一行的文件 i/o;可能还有更好的,我不知道。
我看到了一个我没有调查的意外异常:以下时间
用于常量字符串正则表达式/foobar/。当我将其更改为
/[f][o][o][b][a][r]/ 实际运行正则表达式引擎,grep 减慢
下降 3 倍,而节点加速! grep 的 3 倍减速在
命令行。
filename = "/var/log/apache2/access.log"; // 2,540,034 lines, 187MB
//filename = "/var/log/messages"; // 25,703 lines, 2.5MB
//filename = "out"; // 2000 lines, 188K (head -2000 access.log)
//filename = "/etc/motd"; // 7 lines, 286B
regexp = /foobar/;
child_process = require('child_process');
qfgets = require('qfgets');
function grepWithFs( filename, regexp, done ) {
fp = new qfgets(filename, "r");
function loop() {
for (i=0; i<40; i++) {
line = fp.fgets();
if (line && line.match(regexp)) process.stdout.write(line);
}
if (!fp.feof()) setImmediate(loop);
else done();
}
loop();
}
function grepWithFork( filename, regexp, done ) {
cmd = "egrep '" + regexp.toString().slice(1, -1) + "' " + filename;
child_process.exec(cmd, {maxBuffer: 200000000}, function(err, stdout, stderr) {
process.stdout.write(stdout);
done(err);
});
}
测试:
function fptime() { t = process.hrtime(); return t[0] + t[1]*1e-9 }
t1 = fptime();
if (0) {
grepWithFs(filename, regexp, function(){
console.log("fs done", fptime() - t1);
});
}
else {
grepWithFork(filename, regexp, function(err){
console.log("fork done", fptime() - t1);
});
}
结果:
/**
results (all file contents memory resident, no disk i/o):
times in seconds, best run out of 5
/foobar/
fork fs
motd .00876 .00358 0.41 x 7 lines
out .00922 .00772 0.84 x 2000 lines
messages .0101 .0335 3.32 x 25.7 k lines
access.log .1367 1.032 7.55 x 2.54 m lines
/[f][o][o][b][a][r]/
access.log .4244 .8348 1.97 x 2.54 m lines
**/
(上面的代码都是一个文件,为了避免滚动条,我把它分开了)
编辑:突出显示关键结果:
185MB,254万行,搜索RegExp /[f][o][o][b][a][r]/:
grepWithFs
经过:0.83 秒
grepWithFork
经过:0.42 秒