2017-02-08 42 views
0

我想比较JS EventEmitter和RxJS的性能。我写了下面的基准脚本来做到这一点:EventEmitter vs RxJS vs Kefir

性能测试

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}); 

性能结果

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 

正如你们所看到酸牛奶竟然是最慢违背要求在这link

  1. 我在编写测试中做错了什么?
  2. 如果有人能解释为什么 发生,那将是非常好的。特别是当你将它与javascript event-emitter进行比较时。
+1

1)该链接是RxJS 4,最新版本是v5,这是我认为你正在使用的。 v5从头开始重建,重点在于性能。 2)你没有比较库之间的相同操作,你为RxJS添加了'do',并且正在使用'scan'来开发Kefir。 3)你究竟在想什么?像这样的微不足道的基准测试并没有真正告诉你任何关于库的行为的任何可观的规模。 – paulpdaniels

+0

我想比较EventEmitters和Reactive Programming Frameworks之间的性能。哪一个会更高效。我想知道这些性能差异背后的原因。由于我是反应式编程的新手,我不知道所有的功能。我只是用我能找到的第一件事来总结数组中的值。如果你能推荐更好的基准测试技术,那将是非常好的。谢谢 – pntripathi9417

回答

1

我知道你前一段时间问过这个问题,但我认为给未来的读者一些关于我在基准测试时注意到的问题可能会有帮助。

首先,count不是Kefir中的一个数字,它是一个流。拨打scan后,尝试记录count。而且重要的是,似乎开菲尔count流从来没有被激活,计算永远不会运行!这需要先解决。我怀疑Rx基准测试也是如此,但是您必须查看文档以查看从ES可观察性创建流是否会阻塞。

我相信你可以实现与类似(未测试的代码)的东西,库异步测试:

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

考虑到这一点,这是很奇怪的酸牛奶的基准是最慢的,因为它确实没有工作。我怀疑测试阵列太小,计算得太快而无法获得有价值的基准。测试可能实际上是测量流的构建时间,或者是运行时运行时运行时收集的最多垃圾收集/处理的基准测试。事实上,如果Rx基准测试不会等待测试完成,那么它将进行处理/垃圾清理DURRING Kefir测试!您可以通过等待Kefir和Rx测试在基准测试中完成来减轻这一点;通过在基准之间重新使用通用的全局测试数组来创建更少的垃圾;并使用一个非常非常大的数组来确保迭代是测试基准测试时间的主要因素。

最后,异步基准(酸牛奶和Rx),你需要确保的基准测试处理事件对于事件循环的方式相同。我确定Kefir示例在事件循环的不同tick中处理每个事件,并且必须等待浏览器的其他任何活动(渲染/绘画,其他回调/超时等)在每个步骤之间完成流。请看下面的代码的输出:

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

此代码将始终打印acb在打印最终b未成年人,非零延迟。

我相信你可以得到酸牛奶处理与像Kefir.constant([1,2,3...10]).flatten()一样滴答的阵列。但是,我认为比较同步基准测试中的两个流式框架并不是很有用,因为这不是它们的预期目的。

最后,scan操作比在其他框架一个forEach/do语义上不同,因为它在任何潜在听众每个步骤产生用于输出流的值,而其它仅具有要运行的代码的一个块。

基准很难得到正确的结果,但我希望这有助于。

相关问题