注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

snoopyxdy的博客

https://github.com/DoubleSpout

 
 
 

日志

 
 

利用libuv编写异步多线程的addon实例  

2013-05-22 23:41:31|  分类: node |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
最近cnode上很多TX在问关于node的异步回调以及单线程的事情,今天看了libuv的一些api和demo,自己简单写了一个利用libuv实现异步多线程的addon的例子,真心希望大牛指正啊。

demo例子的地址:
也可以
npm install libuv_ex
请保证您的node版本在0.10.x

首先介绍下libuv,libuv 是一个高性能事件驱动的程序库,封装了 Windows 和 Unix 平台一些底层特性,为开发者提供了统一的 API。libuv 采用了 异步 (asynchronous), 事件驱动 (event-driven)的编程风格, 其主要任务是为开人员提供了一套事件循环和基于I/O(或其他活动)通知的回调函数, libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的支持, 异步访问文件系统, 子进程以及其他功能。
可见nodejs的一切异步操作都是基于libuv来实现的,有了它的这些api我们也就可以编写出异步的nodejs模块了。

最好结合github上的test和liuv.h来看,更加容易弄懂

简单介绍一下这个demo实例把,我在demo里写了5个例子,分别用了不同的技术,执行了10次fibo(40),最后所得到的结果也各不相同。
c++代码都在 ./src  文件夹中,Asyn类中定义了下述5种不同情况的方法和一些libuv的api所需要的回调函数,在job类中,定义了执行fibo的任务函数,和一些相关设置,在线程中或者异步回调中传递的都是job类的指针。
例子执行代码如下:
//do fibo 10 times
var i = 40;
var times = 10;

asyn.sync(times,i,function(err, result){ //1、这里执行10次fibo(40)的函数,分别用不同的技术
console.log('fibo('+i+'):' + result)
})

var d1 = Date.now();
while(Date.now() - d1 <= 1000*1){ //2、这里将主线程sleep 1秒,模拟js的执行工作
//sleeping 10sec simulate the js work
}

我们分别以5种不同的方式执行10次fibo(40),看看测试结果会是什么样子的,我们主要记录全部执行任务的时间和模拟的js任务执行的时间。

1、完全同步,在c++代码中直接10次循环执行fibo(40)
执行测试代码:

main_thread_js_work: 4568ms
sync_all_the_work: 4568ms

可见js执行完毕和所有任务执行完成是同一时间的,这个结果合情合理


2、使用libuv创建同步线程来计算fibo,然后将结果回调主线程
执行测试代码:

main_thread_js_work: 4595ms
sync_thread_all_the_work: 4595ms

由于整个程序都是同步的,所以和之前一样,同步的多线程没有明显提升结果


3、使用libuv的async异步回调方式,将所有任务注册到事件循环中,这样将先执行js的sleep,然后在主线程中分别计算fibo的结果,这种情况有点像我们使用process.nextTick来让一个计算异步执行,保证当前主线程的工作不被阻塞,最后进行耗时计算。
执行测试代码:

main_thread_js_work: 1003ms

asyn_all_the_work: 4457ms

因为我们将fibo放在了异步去执行,所以js的任务将被先执行,js任务执行了1秒(我们模拟sleep了1秒)之后就是fibo的任务,总时间和上面两种情况大致相同。


4、使用libuv的async异步回调的方式,我们先注册fibo执行完毕的异步回调函数,然后创建异步的线程去执行fibo,这样js的任务将和fibo线程同时进行工作.

main_thread_js_work: 1017ms

asyn_thread_all_the_work: 1897ms

因为js任务抢占着主线程,同时也是因为js任务执行时间比较短,所以js任务结束提示先打印到了屏幕上,然后各异步线程也执行完毕,总耗时1897ms,比上面几种情况要快一倍,这主要归功于多核CPU的同时计算


5、使用libuv自带的线程池进行异步计算fibo,我们先向线程池注册工作回调,然后再注册主线程的完成回调

main_thread_js_work: 1002ms
asyn_pool_all_the_work: 2382ms

这种情况和上述情况一样,不过我们不是为每个计算生成一个线程,而是使用了libuv内部的线程池,所以制约了并行计算的能力,但是这样更加安全,不容易因为不可控的线程数量导致程序崩溃,事实上libuv为我们提供了4个线程的线程池。

总结一下,使用libuv我们最好采用可控的异步线程配合异步回调来做一些事情,这样可以不阻塞主的js线程,还能并行执行任务,当任务结束后记得一定要回调主线程去执行js的回调函数,不能在其他线程去执行js的回调,因为在v8的一个isolate中,不可以多个线程同时操作一个isolate。当我们在线程中操作共享变量时记得加锁和解锁。在异步任务执行完毕后记得执行uv_close,将其关闭,同时因为我们都是将指针作为参数传递的,不要忘记delete掉之前new的指针,这样通过libuv的异步多线程api,我们就可以很轻松的为nodejs编写一些跨平台非阻塞扩展了。
PS,经过在win8 64位 和 linux 2.6.4 32bit虚拟机的测试中,我发现win8真是弱爆了,linux虚拟机执行上述任务的所消耗时间比我真机win8还要少一些。
  评论这张
 
阅读(5877)| 评论(1)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016