`
hongtoushizi
  • 浏览: 359276 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

nodejs多线程,真正的非阻塞

阅读更多

干货:收藏: http://cnodejs.org/topic/518b679763e9f8a5424406e9

node从他推出至今,充满赞美和饱受诟病的都是其单线程模型,所有的任务都在一个线程中完成(I/O等例外),优势的地方自然是免去了频繁切换线程的开销,以及减少资源互抢的问题等等,但是当nodejs面对cpu密集型模型的时候就力不从心了。尽管node拥有异步机制,可以把一些耗时算法丢入eventloop等待下个事件循环再做,但是因为其任然是单线程模型,所以终究会造成阻塞。

先解释一下两个名词,Fibers 和 Threads。
Fibers 又称纤程,可以理解为协同程序,类似py和lua都有这样的模型。使用Fibers可以避免对资源的互抢,减少cpu和内存的消耗,但是Fibers并不能够真正的并行执行,同一时刻只有一个Fibers在执行,如果在其中一个Fibers中执行过多的cpu操作或者写了个死循环,则整个主程序将卡死住。node中的异步事件循环模型就有点象这个。

Threads 又称线程,他可以在同一时刻并行的执行,他们共享主进程的内存,在其中某一时刻某一个threads锁死了,是不会影响主线程以及其他线程的执行。但是为了实现这个模型,我们不得不消耗更多的内存和cpu为线程切换的开销,同时也存在可能多个线程对同一内存单元进行读写而造成程序崩溃的问题。

很多让node支持多线程的方法是使用c/c++的addon来实现,在需要进行cpu密集型计算的地方,把js代码改写成c/c++代码,但是如果开发人员对c++不是很熟悉,一来开发效率会降低不少,二来也容易出bug,而且我们知道在addon中的c++代码除了编译出错外,是很难调试的,毕竟没有vs调试c++代码方便。

令人振奋的消息,我们为什么不让node也支持多线程模型呢?于是Jorge为我们开发出了一个让node支持多线程模型的模块:threads_a_gogo
github地址:https://github.com/xk/node-threads-a-gogo

有了threads-a-gogo(以下简称TAGG)这个模块之后,我们可以让node做更多的事情,我记得以前我看过一篇文章,说node只能应付i/o密集型场景,在cpu密集型场景将完败给apache,因为apache是为每一个请求起一条线程的,所以在处理cpu密集型任务时一个线程的高强度计算不会很大程度的影响其他线程,类似的还有php的fastcgi,这也是很多拿node和php进行比较时,php的拥护者们一直提出的理论。

我们先来做一个简单的测试,用我们suqian大大最喜欢的斐波那契数组来看一下,加入了多线程的node有多么的强悍:(测试机器为4CPU)
没有使用TAGG的正常情况,异步也帮不了我们应对cpu密集型任务

function fibo (n){return n >1? fibo(n -1)+ fibo(n -2):1;}var n=8function back(){if(!--n)return console.timeEnd('no thread');}
    console.time('no thread');

    process.nextTick(function(){
        console.log(fibo (40));
        back();})
    process.nextTick(function(){
        console.log(fibo (40));
        back();})
    process.nextTick(function(){
        console.log(fibo (40));
        back();})
    process.nextTick(function(){
        console.log(fibo (40));
        back();})

    process.nextTick(function(){
        console.log(fibo (40));
        back();})

process.nextTick(function(){
    console.log(fibo (40));
    back();})
process.nextTick(function(){
    console.log(fibo (40));
    back();})
process.nextTick(function(){
    console.log(fibo (40));
    back();})

我们模拟了8个异步的行为,测试用的node v0.8.16版本,所以 process.nextTick还是异步方法。最后我们输出结果为:

165580141165580141165580141165580141165580141165580141165580141165580141no thread:23346ms

接下来我们使用TAGG模块来测试同样的执行8次斐波那契数组计算,看看成绩如何?

function fibo (n){return n >1? fibo(n -1)+ fibo(n -2):1;}
console.time('8 thread');var numThreads=8;//创建线程池,最大数为8var threadPool=require('threads_a_gogo').createPool(numThreads).all.eval(fibo);//为线程池注册程序var i=8;var cb =function(err,data){//注册线程执行完毕的回调函数
    console.log(data);if(!--i){
        threadPool.destroy();
        console.timeEnd('8 thread');}}
threadPool.any.eval('fibo(40)', cb);//开始向线程池中执行fibo(40)这个任务

threadPool.any.eval('fibo(40)', cb);

threadPool.any.eval('fibo(40)', cb);

threadPool.any.eval('fibo(40)', cb);

threadPool.any.eval('fibo(40)', cb);

threadPool.any.eval('fibo(40)', cb);

threadPool.any.eval('fibo(40)', cb);

threadPool.any.eval('fibo(40)', cb);

最重的结果:

1655801411655801411655801411655801411655801411655801411655801411655801418 thread:9510ms

相比不使用多线程模型的node,使用了TAGG模块之后,我们在4CPU服务器上的测试结果要快上一倍还不止。
到这里我们看上去找到了一个比较完美的解决方案应对CPU密集型任务,但是可能有同学会说,我可以使用cluster来做相同的事情,下面我们来做一个使用cluster计算这些任务的情况:

var cluster =require('cluster');var numCPUs =8;function fibo (n){return n >1? fibo(n -1)+ fibo(n -2):1;}
console.time('8 cluster');if(cluster.isMaster){// Fork workers.for(var i =0; i < numCPUs; i++){
    cluster.fork();}var i =8;
  cluster.on('exit',function(worker, code, signal){if(!--i){
            console.timeEnd('8 cluster');
            process.exit(0);}});}else{
    console.log(fibo (40));
    process.exit(0);}

代码上的复杂程度比使用TAGG要高的多,而且如果是动态计算斐波那契数组的结果,编码将更加困难,需要在fork时挂上不同的参数,出错的几率也更大。同时还有更重要的一个事情,如果是创建一个http服务器,如果4个cluster都在计算fibo,那第5个请求node将无法处理,而是用TAGG则还是能够正常处理的,所以cluster并不能解决单线程模型的cpu密集计算带来的阻塞问题,我们看下测试结果:

1655801411655801411655801411655801411655801411655801411655801411655801418 cluster:11925ms

TAGG模块还有其他更多的功能,比如事件触发,平滑退出,查看线程工作状态等等,总之TAGG模块给node注入了新的活力,让node一直饱受诟病的处理cpu密集任务问题得到了一个妥善的解决,就算你不擅长c++代码,也能够轻松编写出多线程的真正的非阻塞node程序了。

最后分享一篇干货文章,相当很精彩的一篇博客:
Fibers and Threads in node.js – what for?

tagg2,nodejs多线程模块,更好的api,支持nodejs原生模块,跨平台支持,windows,linux和mac
跨平台模块tagg2,让node多线程支持

 

分享到:
评论

相关推荐

    node.js使用cluster实现多进程

    非阻塞语言! nodeJS 是一门单线程!异步!非阻塞语言! nodeJS 是一门单线程!异步!非阻塞语言! 重要的事情说3遍。 因为nodeJS天生自带buff, 所以从一出生就受到 万千 粉丝的追捧(俺,也是它的死忠). 但是,傻逼php 竟然...

    NodeJS实现同步的方法

    NodeJS被打上了单线程、非阻塞、事件驱动…..等标签。 在单线程的情况下,是无法开启子线程的。经过了很久的研究,发现并没有thread函数!!!但是有时候,我们确实需要“多线程”处理事务。nodeJS有两个很基础的api...

    NodeJS入门手册和64bit安装EXE

    nodejs作为一个新兴的后台语言,有很多吸引人的地方: 1.RESTful API 2.单线程 3.非阻塞IO 4.Google V8 5.事件驱动

    opencv4nodejs

    除了同步 API 之外,该包还提供异步 API,它允许您构建非阻塞和多线程计算机视觉任务。 opencv4nodejs 支持 OpenCV 3 和 OpenCV 4。 该项目的最终目标是提供与 OpenCV API 和 OpenCV-contrib 模块的 Nodejs 绑定的...

    opencv4nodejs:Nodejs绑定到OpenCV 3和OpenCV 4

    除了同步API外,该软件包还提供了一个异步API,使您可以构建非阻塞和多线程计算机视觉任务。 opencv4nodejs支持OpenCV 3和OpenCV 4。 该项目的最终目标是提供与OpenCV API和OpenCV-contrib模块的nodejs绑定的全面...

    NodeJS如何实现同步的方法示例

    下面这篇文章主要介绍了关于NodeJS实现同步的相关内容,NodeJS被打上了单线程、非阻塞、事件驱动…..等标签。 在单线程的情况下,是无法开启子线程的。经过了很久的研究,发现并没有thread函数!!!但是有时候,...

    matlab人脸检测框脸代码-opencv4nodeJs-4.5.2:适用于Node.js的OpencvBuild

    除了同步API外,该软件包还提供了一个异步API,使您可以构建非阻塞和多线程计算机视觉任务。 opencv4nodejs支持OpenCV 3和OpenCV 4。 该项目的最终目标是提供与OpenCV API和OpenCV-contrib模块的nodejs绑定的全面...

    Node.JS中事件轮询(Event Loop)的解析

    NodeJS采用单线程非阻塞的架构解决老大难的IO问题 当采用多线程时,为每一个请求开启一个新的线程(Apache就是这样做的)。当并发增多,线程的消耗会十分严重。 什么是阻塞和非阻塞呢? 阻塞调用是指

    NodeCluster:了解NodeJS集群模块

    Node.js具有事件驱动的体系结构,利用了非阻塞I / O API,该API允许异步处理请求。 每个Node.js进程都在单个线程中运行,默认情况下,它在32位系统上的内存限制为512MB,在64位系统上的内存限制为1GB。 尽管在32位...

    NodeJS搭建本地服务指南

    Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。  Node 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。 Node的优点  Node...

    --Awesome-NodeJS--:JIT编译JS运行时。 学习快递,考阿,哈皮

    它的设计与受Ruby事件机器,Python的Twisted等非阻塞I / O和异步处理系统影响的设计相似。 对于包和依赖项管理,就像JavaScript一样,我们使用npm,这是世界上最大,功能最强大的包生态系统和依赖项管理软件。 ...

    java抓取网页数据源码-neocrawler:NodejsCrawler,包括schedule、spider、webuiconfig、pro

    由于nodejs语言本身非阻塞、异步的特性,运行爬虫这类IO密集CPU需求不敏感的系统表现很出色,与其他语言的版本简单的比较,开发量小于C/C++/JAVA,性能高于JAVA的多线程实现以及Python的异步和携程方式的实现。...

    Node.js 多进程处理CPU密集任务的实现

    大家都知道 Node.js 性能很高,是以异步事件驱动、非阻塞 I/O 而被广泛使用。但缺点也很明显,由于 Node.js 是单线程程序,如果长时间运算,会导致 CPU 不能及时释放,所以并不适合 CPU 密集型应用。 当然,也不是...

    Node.js(node-v16.15.1-linux-arm64.tar.xz)

    Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用程序运行单线程,尽管 Node.js 使用多个线程来处理文件和网络事件。由于 Node.js 的异步特性,它通常用于实时应用程序。 ...

    Node.js(node-v16.15.1-win-x64.zip)

    Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用程序运行单线程,尽管 Node.js 使用多个线程来处理文件和网络事件。由于 Node.js 的异步特性,它通常用于实时应用程序。 ...

    Node.js(node-v16.15.1-x86.msi)

    Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用程序运行单线程,尽管 Node.js 使用多个线程来处理文件和网络事件。由于 Node.js 的异步特性,它通常用于实时应用程序。 ...

    初始Nodejs

    基本概念 Node.js,或者 Node,是一个可以让 JavaScript 运行在服务器端的平台。可以说,Node.js开创了javascript模块化开发的先河,早期的...其最初目标是实现事件驱动,非阻塞I/O的web服务器 Node.js 只是一个

    Node.js(node-v16.15.1-darwin-arm64.tar.gz)

    Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用程序运行单线程,尽管 Node.js 使用多个线程来处理文件和网络事件。由于 Node.js 的异步特性,它通常用于实时应用程序。 ...

    harmonyos2-waitfor-ES6:node.js和浏览器的顺序编程。回调地狱的结束-原始Wait.for,使用即将推出的javas

    没有多线程调试噩梦,在给定时间只运行一根光纤。 可以使用任何带有 callback(err,data) 作为最后一个参数的节点标准异步函数。 与节点编程风格一起玩。 使用 callback(err,data) 编写异步函数,但在需要时以顺序/...

    Node.js(node-v16.15.1-aix-ppc64.tar.gz)

    Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用程序运行单线程,尽管 Node.js 使用多个线程来处理文件和网络事件。由于 Node.js 的异步特性,它通常用于实时应用程序。 ...

Global site tag (gtag.js) - Google Analytics