手机版

nodejs多线程编程示例

时间:2021-09-09 来源:互联网 编辑:宝哥软件园 浏览:

在之前的博文《不要说不可能,在nodejs中实现睡眠》中,我给大家介绍了nodejs插件的用法。今天的话题是addon,它将继续挖掘c/c的能力,弥补nodejs的弱点。

我已经多次提到nodejs的性能问题。其实就语言本身而言,nodejs的性能还是很高的。虽然不如大多数静态语言,但差距不大;与其他动态语言相比,速度优势明显。但是为什么我们经常说nodejs不能胜任CPU密集型的场景呢?由于单线程的特点,对于CPU密集型的场景,无法充分利用CPU。计算机科学中有一个著名的阿姆达尔定律:

假设总工作量为W,可以分为两部分:只能串行计算的Ws和允许并行计算的Wp。然后,在p CPUs并行计算的情况下,可以通过加速时间来提高性能。阿姆达尔定律描述了什么可以并行完成,什么不能并行完成。这是一个理想的情况,实际情况会复杂得多。比如并发很可能会造成资源的竞争,需要添加各种锁,往往会让并行等待;并发还会给操作系统调度和切换线程带来额外的时间成本,增加Ws。然而,当一个任务中的Wp远大于Ws,并且有多个CPU内核可用时,并行带来的性能提升是相当可观的。

好吧,回到nodejs。我们设想一个计算场景:计算4000000以内的素数。这个场景在编程实现时,主要是基于除法运算,不涉及内存、对象等操作。理论上可以保证nodejs运行速度比较快,不会比C落后太多,便于比较。

本博客提供了javascript查找质数的方法,直接复制:

复制代码如下:函数zhi Shu _ js(num){ if(num==1){ return false;} if(num==2){ return true;} for(var I=2;I=Math . sqrt(num);I){ if(num % I==0){ return false;} }返回true}

再写一个c语言版本:复制代码如下:#include math.h

bool zhi Shu(int num){ if(num==1){ return false;} if(num==2){ return true;} for(int I=2;I=sqrt(num);I){ if(num % I==0){ return false;} }返回true};

在nodejs中,我们使用从1到4000000的循环来检索素数;在C语言中,我们设置了几个线程,并将计数定义为400000。每个线程都要做以下操作:如果count大于0,则取出计数值,计算是否为素数,将count减1。按照这个思路,javascript版本很容易写:复制代码如下: var count=0;

for(j=1;4000000j;j){ if(zhi Shu(j)){ count;}}

关键难点是C语言的多线程编程。早期的c/c没有考虑并行计算的需求,所以标准库没有提供多线程支持。不同的操作系统通常有不同的实现。为了避免这个麻烦,我们使用pthread来处理线程。

下载最新版本的pthread。因为不熟悉gyp,link长期依赖lib。最后,我的方法是直接将pthread的源代码放在项目目录中,在binding.gyp中的源代码列表中添加pthread.c,在编译项目时编译一次pthread。修改后的binding.gyp是这样的:复制的代码如下: { ' targets ' :[{ ' target _ name ' : ' hello ',' sources' : ['hello.cc ',' pthreads/pthread.c'],' include _(node-e ' require(' nan ' \ '))',' pthreads' ],' libraries ' :[' Ws2 _ 32 . lib ']} }

当然,我的方法很麻烦。如果你只在pthread中添加lib和include目录的引用,并且没有依赖问题,那是最好的,所以没必要用我的方法。

然后,输入关于C/C多线程的一切,定义一个线程处理函数:复制代码如下:pthread _ mutex _ t lock

void * thread _ p(void * null){ int num,x=0;do{ pthread_mutex_lock(锁定);num=count-;pthread_mutex_unlock(锁定);if(num 0){ if(zhi Shu(num))x;} else { break} } while(true);std:cout ' ' xpthread_exit(空);返回null}

线程之间,变量计数是相互竞争的,所以我们需要保证只有一个线程可以同时操作变量计数。我们传递pthread_mutex_t锁;添加互斥体。执行pthread_mutex_lock(锁)时;线程检查锁,如果被锁定,则等待并重复检查,以阻止后续代码运行;如果锁被释放,锁定它并执行后续代码。相应地,pthread_mutex_unlock(锁定);是解锁状态。

因为编译器是在编译的同时进行编译优化的,如果一条语句没有显式地做什么,对其他语句的执行没有影响,那么它就会被编译器优化。在上面的代码中,我添加了计算质数的代码,如果没有,代码如下:复制代码如下: for(int j=0;4000000j;j){ zhi Shu(j);}

被编译器直接跳过,实际上不会运行。

介绍了添加插件的编写方法。我们实现从javascript中接收一个参数,指示线程数,然后在C中创建指定数量的线程,完成素数检索。完整代码:复制的代码如下: # include an . h # include eash . h # include eaiostream # include ' pthreads \ pthread . h ' # define max _ thread 100使用命名空间V8;

int count=4000000pthread _ t tid[MAX _ THREAD];pthread_mutex_t锁;

void * thread _ p(void * null){ int num,x=0;do{ pthread_mutex_lock(锁定);num=count-;pthread_mutex_unlock(锁定);if(num 0){ if(zhi Shu(num))x;} else { break} } while(true);std:cout ' ' xpthread_exit(空);返回null}

NAN _ METHOD(Zhishu){ NanScope();pthread_mutex_init(锁,空);double arg 0=args[0]-NumberVaLue();int c=0;for(int j=0;j arg0 jMAX _ THREADj ) { pthread_create(tid[j],NULL,thread_p,NULL);} for(int j=0;j arg0 jMAX _ THREADj ) { pthread_join(tid[j],NULL);} NanReturnUndefined();}

void Init(HandleObject exports){ exports-Set(NanSymbol(' Zhishu '),function template : new(Zhishu)-GetFunction());}

NODE_MODULE(你好,Init);

Phread_create可以创建一个线程,默认情况下是可以连接的。此时子线程服从主线程;Phread_join阻塞主线程,等待子线程加入,直到子线程退出。如果子线程已经退出,phread_join将什么也不做。因此,在所有线程上执行thread_join可以确保所有线程在主线程继续之前退出。

改进nodejs脚本:复制代码如下:varzhishu _ c=require('。/build/release/hello.node ')。致书;函数zhi Shu(num){ if(num==1){ return false;} if(num==2){ return true;} for(var I=2;I=Math . sqrt(num);I){ if(num % I==0){ return false;} }返回true}

console . time(' c ');智书_ c(100);console . timeend(' c ');

console . time(' js ');var计数=0;for(j=1;4000000j;j){ if(zhi Shu(j)){ count;}}console.log(计数);console . timeend(' js ');

看看测试结果:

在单线程中,虽然C/C的运行速度是nodejs的181%,但这个成绩在动态语言中还是很不错的。速度提升最明显的是在双线程的情况下,因为我的电脑是双核四线程的CPU,此时有可能使用两个内核进行处理。4个线程,这应该是双核四个线程所能达到的极限。当线程数再次增加时,速度就无法再提高了。在上面的Amdahl定律中,p已经达到了4的上限。添加更多线程将增加操作系统进程的调度时间和锁定时间。虽然也能增加对CPU时间的竞争,但总体来说,Ws的增加比较明显,性能在下降。如果我们在空闲机器上做这个实验,数据会更好。

从这个实验中,我们可以得出结论,对于CPU密集型的操作,将它们交给静态语言会大大提高效率。如果计算中涉及更多的内存、字符串、数组、递归等操作(后面会验证),性能会更加惊人。同时,合理使用多线程可以有效提高处理效率,但并不是线程越多越好。应根据机器情况合理配置。

Nodejs本身确实不擅长处理CPU密集型的任务,但是以本文的经验,我认为克服这个障碍也不是不可能的。

版权声明:nodejs多线程编程示例是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。