Javascript EventEmitter vs RxJS vs Kefir
我想比较JS EventEmitter和RxJS的性能。为此,我编写了以下基准脚本: 性能测试Javascript EventEmitter vs RxJS vs Kefir,javascript,rxjs,dom-events,kefir.js,Javascript,Rxjs,Dom Events,Kefir.js,我想比较JS EventEmitter和RxJS的性能。为此,我编写了以下基准脚本: 性能测试 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
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});
正如你所看到的,凯菲尔最终证明是最慢的,这与当时的说法相反
我知道你刚才问过这个问题,但我认为让未来的读者了解我在查看基准时注意到的一些问题可能会有所帮助 首先,
count
不是Kefir中的数字,它是一个流。在调用scan
后尝试记录count
。重要的是,Kefircount
流似乎从未激活,计算也从未运行过!这需要先解决。我怀疑Rx基准测试也是如此,但您必须检查文档,看看从一个可观测的对象创建流是否会阻塞
我相信您可以使用类似于(未测试代码)的库实现异步测试:
考虑到这一点,很奇怪Kefir的基准测试是最慢的,因为它不起作用。我怀疑测试阵列太小,计算速度太快,无法获得有价值的基准测试。很可能测试实际上是在测量流构造时间,或者是在运行时,运行时垃圾收集/处理最多的基准测试。事实上,如果Rx基准不等待测试完成,那么它将在Kefir测试期间进行处理/垃圾清理!您可以通过等待Kefir和Rx测试在基准测试中完成来缓解这一问题;通过在基准测试之间重用一个通用的全局测试数组来减少垃圾;使用一个非常非常大的数组来确保迭代在基准测试中占主导地位
最后,对于异步基准(Kefir和Rx),您需要确保基准以与事件循环相同的方式处理事件。我确信Kefir示例在事件循环的不同刻度中处理每个事件,并且必须等待浏览器的任何其他活动(渲染/绘制、其他回调/超时等)在流中的每个步骤之间完成。考虑以下代码的输出:
console.log('a')
setTimeout(function() {
console.log('b')
}, 0);
console.log('c')
此代码将始终打印a
、c
、b
,打印最终b
时有一个较小的非零延迟
我相信您可以让Kefir在相同的时间内使用类似于Kefir.constant([1,2,3…10]).flatten()的东西来处理数组。然而,我不认为在同步基准中比较这两个流框架是非常有用的,因为这不是它们的预期目的
最后,scan
操作在语义上不同于其他框架中的forEach
/do
,因为它在每一步为任何潜在侦听器生成一个输出流值,而其他侦听器只需运行该代码块
基准测试很难做到正确,但我希望这会有所帮助。1)该链接适用于RxJS 4,最新版本是v5,我认为您正在使用该版本。v5是从头开始重建的,重点是性能。2) 您没有比较库之间的相同操作,而是为RxJS添加了一个do
,并为Kefir使用scan
。3) 你到底想做什么?像这样的琐碎的基准测试并不能真正告诉你任何关于库在任何可感知的规模上的行为。我想比较EventEmitter和反应式编程框架之间的性能。哪一个性能更好。我想知道这些性能差异背后的原因。因为我是反应式编程的新手,所以我不知道所有的函数。我只是用我能找到的第一件事来对数组中的值求和。如果您能推荐更好的基准测试技术,那就太好了。谢谢
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})
console.log('a')
setTimeout(function() {
console.log('b')
}, 0);
console.log('c')