• 首页
  • nodejs
  • async和eventproxy在流程控制上哪个更优秀

async和eventproxy在流程控制上哪个更优秀


由于node.js特性异步IO,导致 node.js 开发常常让你头疼的是异步嵌套回调.

一层一层的大括号嵌套让你当场就迷失在回调函数中,更不用说隔一段时间自己去维护这段代码的时候,恨不能砸显示器来泄愤.

不过这个世界还是美好的,你遇到的问题大家也都遇到了,而且大牛们致力于减轻码农的各种node.js 的痛苦,开发出了高效好用的流程控制包,让你的逻辑变的清晰,维护起来一目了然.

常用的有 async ,step ,eventproxy

step本人接触很少,一直在用async,也是最近注意到了 eventproxy ,我想看看哪个性能更优,代码更加优雅,所以有了下面一个小demo.


这个demo不去比较实现原理,内部代码,而仅仅是从使用的角度,看一下在多个逻辑嵌套的情况下哪个速度稍微快一点,不太感兴趣的可以直接忽略下面内容.


首先需要引入 async 和 eventproxy npm包.

npm install async eventproxy


var EventProxy = require('eventproxy');

var async = require('async');


为了排除外界的干扰,我的逻辑测试代码没有涉及到网络请求,没有数据库,文件io处理,仅仅是一个消耗cpu的数学计算,我选择了 斐波纳契数列之和,很简单的数列,不明白的可以问度娘.

斐波纳契数列是这样的数列:1、1、2、3、5、8、13、21、……

数学模型上的实现方法是这样:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2)

数列的每个值是前面2个值的和.现在我们要求一个数值对应的斐波纳契数列之和,如果数值足够大,这个程序的递归迭代还是很耗cpu的.

代码实现如下:


function step1(n) {

if (n > 2)

return step1(n - 1) + step1(n - 2);

else

return 1;

}


在流程控制过程中,求一个数值的斐波纳契数列之和就表示一个业务逻辑处理,所以为了模拟一系列逻辑处理节点.

我需要给多个数值求斐波纳契数列,所以干脆我定义一个数组.

var len,val = [],

arr = [36, 39, 38, 31, 36,37,29,24,28,37,35,33,38,35,37];

len在后面会保存arr数组长度,val数组用来存放元素 斐波那契数列之和 .

上面的15个数字代表15次逻辑处理.


(一)用数组for循环15次逻辑处理,然后用计数器自动记录处理次数.最后返回保存斐波那契数列和的数组 val.


//for

console.time('for_time');

len = arr.length;

val = [];

console.log('------for循环测试开始------')


for (var i = 0; i < arr.length; i++) {

val.push(step1(arr[i]));


if (--len == 0) {

console.log(val);

console.timeEnd('for_time');

}

}



(二)async 用series串行无关联 和 parallel并行无关联 测试

async下的each /forEach 我随便测试了一下,下面主要看2种流程控制


//async  串行无关联

console.time('async_Series');

val = [];

console.log('------async_Series 测试开始------')

async.series([

  function(done){ 

      //逻辑处理

      done(null,val.push(step1(arr[0])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[1])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[2])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[3])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[4])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[5])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[6])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[7])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[8])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[9])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[10])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[11])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[12])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[13])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[14])));

  }

],function(error,result){

    //最后结果

  console.log(val);

console.timeEnd('async_Series');

});



//async 并行无关联

console.time('async_parallel');

val = [];

console.log('------async_parallel 测试开始------')

async.parallel([

  function(done){ 

      //逻辑处理

      done(null,val.push(step1(arr[0])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[1])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[2])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[3])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[4])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[5])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[6])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[7])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[8])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[9])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[10])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[11])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[12])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[13])));

  },

  function(done){

      //逻辑处理

      done(null,val.push(step1(arr[14])));

  }

],function(error,result){

    console.log(val);

console.timeEnd('async_parallel');

});


(三)eventproxy 实现流程控制

flag1 到 flag15 手动输入好烦,有没有简单好用的方法.


//eventproxy

console.time('eventproxy');

val = [];

console.log('------eventproxy 测试开始------');

var ep = EventProxy.create("flag1", "flag2", "flag3","flag4","flag5","flag6", "flag7", "flag8","flag9","flag10","flag11", "flag12", "flag13","flag14","flag15",function (flag1, flag2,flag3,flag4,flag5,flag6, flag7,flag8,flag9,flag10,flag11, flag12,flag13,flag14,flag15) {

console.log(val);

console.timeEnd('eventproxy');

});



  ep.emit("flag1", val.push(step1(arr[0])));


  ep.emit("flag2", val.push(step1(arr[1])));


  ep.emit("flag3", val.push(step1(arr[2])));


  ep.emit("flag4", val.push(step1(arr[3])));


  ep.emit("flag5", val.push(step1(arr[4])));


  ep.emit("flag6", val.push(step1(arr[5])));


  ep.emit("flag7", val.push(step1(arr[6])));


  ep.emit("flag8", val.push(step1(arr[7])));


  ep.emit("flag9", val.push(step1(arr[8])));


  ep.emit("flag10", val.push(step1(arr[9])));


  ep.emit("flag11", val.push(step1(arr[10])));


  ep.emit("flag12", val.push(step1(arr[11])));


  ep.emit("flag13", val.push(step1(arr[12])));


  ep.emit("flag14", val.push(step1(arr[13])));


  ep.emit("flag15", val.push(step1(arr[14])));

  

  三种测试方法代码已经完成,下面就运行一下:


上面这一组测试结果很难看出问题,如果你把代码自己运行一下,你会看到所耗时间数据是很跳跃的,尤其像上面 async 的并行方法速度竟然比串行方法速度慢了一大截,一下感觉这个世界也不美好了.(上面的测试结果包含了async 的each 等运行结果,但是上面代码我去掉了这部分)

大概是因为这个密集型cpu运算,导致每个流程把cpu资源都消耗在了斐波那契数列之和的计算上,而真正逻辑处理的时候,由于逻辑处理也就15个,在cpu被计算全部占用后,流程控制上几乎无法比较了.所以这个结果很不稳定,一会eventproxy优于async ,一会又相反的结果.

所以打算让逻辑处理简单一点,不要把cpu压力全部集中在计算上,而让资源也充分体现在流程控制上.于是把上面的15个元素的数组改成了下面这样.

arr = [6, 13, 8, 10, 6,7,9,4,8,14,15,16,6,7,9];

还是15个,但是明显数值都很低.

然会进行下一轮测试:

虽然这么小的样本是无法说明一个结果的,但是在这个不靠谱的测试结果中,我们貌似看到了自己用for循环+计数器控制流程明显是耗时多一点. eventproxy 表现稳定,在这个测试表现最优,async表现有点不稳定 paraller 在 series名下没有表现出并行的优势.有待于更深层次的比较和一个大而全的样本来说服,这次的小测试就看做是一个熟悉代码的学习吧.

回到顶部