如何对Node.js流进行基准测试?

4

如何在Node.js中对进行基准测试?

我尝试过benchmark.js

var fs = require('fs');
var Transform = require('readable-stream').Transform;
var util = require('util');
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;

// my super uppercase stream
function Uppercase(options) {
  if (!(this instanceof Uppercase))
    return new Uppercase(options);

  Transform.call(this, options);
}

Uppercase.prototype = Object.create(
  Transform.prototype, { constructor: { value: Uppercase }});

Uppercase.prototype._transform = function(chunk, encoding, done) {
  chunk = chunk.toString().toUpperCase();
  this.push(chunk)
};

// start benchmarking
suite.add('stream test', function() {
  var reader = fs.createReadStream('in.txt');
  var parser = new Uppercase();
  var writer = fs.createWriteStream('out.txt');
  reader.pipe(parser).pipe(writer);
})
// add listeners
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
// run async
.run();

suite.run();

但是我遇到了错误。
Unhandled stream error in pipe

你确定这个问题与基准测试有关吗?换句话说,当你在基准测试之外尝试 var reader = fs.createReadStream('in.txt'); var parser = new Uppercase(); var writer = fs.createWriteStream('out.txt'); reader.pipe(parser).pipe(writer); 时,是否会抛出相同的错误? - Mathias Bynens
刚刚发现我调用了 run() 两次,但那不是错误的原因。@MathiasBynens 在基准环境之外,代码运行良好。我还为 reader 添加了一个 error 事件处理程序。现在初始错误已经消失了,我得到了 [Error: OK, open 'my\path\to\data.json' - zemirco
你的 Node 版本是多少,使用的是哪个操作系统? - user568109
节点 v0.8.18 和 Mac OS v10.7.5 - zemirco
1个回答

4

您的代码遇到了这个错误,您可以通过监听读取器和写入器上的错误来查看它:

[Error: EMFILE, open 'out.txt'] errno: 20, code: 'EMFILE', path: 'in.txt'
[Error: EMFILE, open 'out.txt'] errno: 20, code: 'EMFILE', path: 'out.txt'

这是由于流是异步的,没有明确的回调来告诉你它们何时结束。因此,您基本上正在在in.txt和out.txt之间创建成千上万个管道流,直到系统告诉您文件描述符太多为止。
所以,我猜测通过“在Node中对流进行基准测试”,您想要计算的是同步执行此操作所需的时间:
reader.pipe(filter).pipe(writer)

在这种情况下,您需要:

这个答案的代码已经在node 0.10.0中进行了测试,但我想唯一的区别应该是持有Transform模块的名称:

var fs = require('fs');
var util = require('util');
var Transform = require('stream').Transform;
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;

var i = 0;

// my super uppercase stream
function Uppercase(options) {
  if (!(this instanceof Uppercase))
    return new Uppercase(options);

  Transform.call(this, options);
}

Uppercase.prototype = Object.create(
  Transform.prototype, { constructor: { value: Uppercase }}
);

Uppercase.prototype._transform = function(chunk, encoding, done) {
  chunk = chunk.toString().toUpperCase();
  this.push(chunk)
};



// start benchmarking
suite.add('stream test', {
  'defer' : true,
  'fn' : function (deferred) {
    var reader = fs.createReadStream('in.txt');
    var parser = new Uppercase();
    var writer = fs.createWriteStream('out.txt');

    reader.on('error', function (err) {
      console.log(err);
    });
    writer.on('error', function (err) {
      console.log(err);
    });
    reader.on('end', function  (argument) {
      // Wait until reader is over and then close reader and finish deferred test
      writer.end();
      deferred.resolve();
    });

    reader.pipe(parser).pipe(writer, {'end': false});
  }
})

//  listeners
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})

// run async
.run();

看起来不错。今晚会尝试这段代码。我以为异步操作可能会导致问题,但不知道 defer 选项。谢谢! - zemirco
只需进行一个小改进:在 parser.on('end', function(){}) 中调用 deferred.resolve(),而不是在 reader.on('end') 中调用,因为后者可能会在我的 parser 完成之前关闭 writer - zemirco
我仍然没有找到答案。但是解析器没有发出结束信号。即使我们像这样调用函数 reader.pipe(parser,{'end': false }).pipe(writer, {'end': false});。我会更深入地研究它。 - fe_lix_
解析器在我们的情况下没有发出任何事件。我已经尝试了所有可读和可写流事件,但仍然没有结果。我实际上不确定这是否是一个特性。 - fe_lix_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接