【问题标题】:How to benchmark Node.js streams?如何对 Node.js 流进行基准测试?
【发布时间】:2013-03-14 15:38:16
【问题描述】:

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

我试过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); 在基准测试之外尝试时会抛出相同的错误吗?
  • 刚刚看到我打电话给run() 两次,但这不是错误。 @MathiasBynens 代码在基准环境之外运行良好。我还为reader 添加了error 事件处理程序。现在初始错误消失了,我得到了[Error: OK, open 'my\path\to\data.json'
  • 您的节点版本是什么,您使用的是哪个操作系统?
  • 节点 v0.8.18 和 mac os v10.7.5

标签: javascript node.js benchmarking


【解决方案1】:

您的代码遇到此错误,您可以通过在 reader 和 writer 上侦听错误来查看它:

[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)

在这种情况下,您需要:

此答案的代码已使用节点 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 选项。谢谢!
  • 只是一个小改进:在parser.on('end', function(){}) 中调用deferred.resolve() 而不是reader.on('end'),因为后者可能会在我的parser 完成之前关闭writer
  • 我仍然没有找到答案。但是解析器不会发出结束信号。即使我们这样调用函数reader.pipe(parser,{'end': false }).pipe(writer, {'end': false});。我会更深入地研究它。
  • 在我们的例子中解析器不会发出任何事件。我已经尝试了所有可读和可写的流事件,但什么也没有。我实际上不确定它是否是一个功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 2012-02-02
  • 2013-05-30
相关资源
最近更新 更多