简体   繁体   English

EventEmitter vs RxJS vs Kefir

[英]EventEmitter vs RxJS vs Kefir

I wanted to compare JS EventEmitter and RxJS performance.我想比较 JS EventEmitter 和 RxJS 的性能。 I wrote following benchmark script to do that:我编写了以下基准脚本来做到这一点:

Performance Test性能测试

import Rx from 'rxjs/Rx';
import Kefir from 'kefir';

import { EventEmitter } from "events";

let Benchmark = require ("benchmark");
let suite = new Benchmark.Suite;

suite
.add('for', () => {
  let numArray = [1,2,3,4,5,6,7,8,9,10];
  let count = 0;
  for (let i = 0; i<numArray.length; i++)
    count += numArray[i];
})
.add('forEach', () => {
  let numArray = [1,2,3,4,5,6,7,8,9,10];
  let count = 0;
  numArray.forEach((num) => { count += num; });
})
.add('eventEmitter', () => {
  let numArray = [1,2,3,4,5,6,7,8,9,10];
  let count = 0;
  let myEmitter = new EventEmitter();
  myEmitter.on('number', (num) => { count += num; });
  numArray.forEach((num) => { myEmitter.emit('number', num); });
})
.add('rxjs', () => {
  let numArray = [1,2,3,4,5,6,7,8,9,10];
  let count = 0;
  let source = Rx.Observable.from(numArray)
    .do((x) => { count += x }, (error) => {}, () => {});
  source.subscribe((x) => {}, (error) => {}, () => {});
})
.add('kefir', () => {
  let numArray = [1,2,3,4,5,6,7,8,9,10];
  let count = 0;
  let stream = Kefir.sequentially(0, numArray);
  count = stream.scan(sum => sum + 1, 0);
})
.on('cycle', function (event) {
  console.log(String(event.target));
})
.on('complete', function () {
  console.log('Slowest is ' + this.filter('slowest').map('name'));
})
.run({'async': true});

Performance Results性能结果

for x 47,595,916 ops/sec ±1.58% (87 runs sampled)
forEach x 4,428,485 ops/sec ±0.75% (86 runs sampled)
eventEmitter x 1,478,876 ops/sec ±0.61% (86 runs sampled)
rxjs x 547,732 ops/sec ±0.66% (86 runs sampled)
kefir x 496,709 ops/sec ±5.15% (50 runs sampled)
Slowest is kefir

As you can see Kefir turned out to be slowest contrary to the claim made at this link .正如您所看到的,与此链接中的声明相反,Kefir 的速度最慢。

  1. Have I done something wrong in writing the test?我在编写测试时做错了什么吗?
  2. It would be great if anyone can explain the difference why does it occur.如果有人能解释为什么会发生这种差异,那就太好了。 Specially when you compare it with javascript event-emitter.特别是当您将它与 javascript 事件发射器进行比较时。

I know you asked this question a while ago, but I think it might be helpful to give future readers an idea of some of the problems I noticed while looking at the benchmarks.我知道您不久前问过这个问题,但我认为让未来的读者了解我在查看基准测试时注意到的一些问题可能会有所帮助。

Firstly, count isn't a number in Kefir, it's a stream.首先, count不是 Kefir 中的数字,它是一个流。 Try logging count after you call scan .在调用scan后尝试记录count And importantly, it seems the Kefir count stream is never activated and the computation is never run!重要的是,似乎 Kefir count流从未被激活并且计算从未运行! That needs to be fixed first.这需要先修复。 I suspect the same is true for the Rx benchmark, but you'll have to check the documentation to see if creating a stream from an ES observable will block or not.我怀疑 Rx 基准测试也是如此,但是您必须检查文档以查看从 ES observable 创建流是否会阻塞。

I believe you can implement an async test with that library with something similar to (untested code):我相信您可以使用类似于(未经测试的代码)的内容使用该库实现异步测试:

suite.add('My async test', function(deferred) {
    let numArray = [1,2,3,4,5,6,7,8,9,10];
    let stream = Kefir.sequentially(0, numArray);
    let countStream = stream.scan(sum => sum + 1, 0);
    countStream.onEnd(() => deferred.resolve());
}, {'defer': true})

With that in mind, it's very strange Kefir's benchmark is the slowest because it does NO WORK.考虑到这一点,很奇怪 Kefir 的基准测试是最慢的,因为它不起作用。 I suspect the test arrays are too small and are calculated too quickly to get a valuable benchmark.我怀疑测试数组太小,计算速度太快,无法获得有价值的基准。 It's likely tests are actually measuring the stream construction times or whichever benchmark happens to have the most garbage collected/processes by the runtime while it's running.很可能测试实际上是在测量流构建时间,或者无论哪个基准恰好在运行时由运行时收集/处理的垃圾最多。 In fact, if the Rx benchmark doesn't wait for the test to finish, it will be doing it's processing/garbage cleanup DURRING the Kefir test!事实上,如果 Rx 基准测试不等待测试完成,它将在 Kefir 测试期间进行处理/垃圾清理! You can mitigate this by waiting for the Kefir and Rx tests to finish in the benchmark;您可以通过等待 Kefir 和 Rx 测试在基准测试中完成来缓解这种情况; create less garbage by reusing a common, global test array between benchmarks;通过在基准测试之间重用通用的全局测试数组来减少垃圾; and use a very, very large array to be sure iteration is what dominates the time spent in the benchmarks.并使用一个非常非常大的数组来确保迭代是在基准测试中花费的时间的主要因素。

Finally, for the asynchronous benchmarks (Kefir and Rx), you need to be sure the benchmarks are processing events the same way with respect to the event loop.最后,对于异步基准测试(Kefir 和 Rx),您需要确保基准测试以与事件循环相同的方式处理事件。 I'm certain the Kefir example processes each event in a DIFFERENT tick of the event loop and will have to wait for any of the browser's other activity (rendering/painting, other callbacks/timeouts, etc.) to complete between each step in the stream.我确定 Kefir 示例在事件循环的不同刻度中处理每个事件,并且必须等待浏览器的任何其他活动(渲染/绘画、其他回调/超时等)在每个步骤之间完成溪流。 Consider the output of the following code:考虑以下代码的输出:

console.log('a')
setTimeout(function() {
    console.log('b')
}, 0);
console.log('c')

This code will always print a , c , b with a minor, nonzero delay in printing the final b .此代码将始终打印acb并在打印最终b有轻微的非零延迟。

I believe you can get Kefir to process the array in the same tick with something like Kefir.constant([1,2,3...10]).flatten() .我相信你可以让开菲尔在同一个滴答声中处理数组,比如Kefir.constant([1,2,3...10]).flatten() However, I don't think it's very useful to compare the two streaming frameworks in a synchronous benchmark because that is not their intended purposes.但是,我认为在同步基准测试中比较两个流框架不是很有用,因为这不是它们的预期目的。

Finally, the scan operation is semantically different than a forEach / do in the other frameworks because it produces a value for the output stream at each step for any potential listeners while the others only have to run that one block of code.最后, scan操作在语义上与其他框架中的forEach / do不同,因为它在每个步骤为任何潜在侦听器的输出流生成一个值,而其他人只需运行该代码块。

Benchmarks are very hard to get right, but I hope this helps.基准很难做到正确,但我希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM