我的编程空间,编程开发者的网络收藏夹
学习永远不晚

nodejs中使用多线程编程的方法实例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

nodejs中使用多线程编程的方法实例

在以前的博文别说不可能,nodejs中实现sleep中,我向大家介绍了nodejs addon的用法。今天的主题还是addon,继续挖掘c/c++的能力,弥补nodejs的弱点。

我曾多次提到过nodejs的性能问题。其实就语言本身而言,nodejs的性能还是很高的,虽然不及大多部静态语言,但差距也并不大;相对其他动态语言而言,速度优势非常明显。但为什么我们常常说nodejs不能胜任CPU密集型场景呢?因为由于其单线程特性,对于CPU密集型场景,它并不能充分利用CPU。计算机科学中有一个著名的Amdahl定律:

查看图片

假设总工作量W,可以分解为两个部分:只能串行计算的Ws和允许并行计算的Wp。那么,在p个CPU并行计算的情况下,性能上能够带来speedup倍的提升。Amdahl定律描述了并行能做到的和不能做到的。它是一种理想情况,实际情况会复杂得多。比如并发很可能会引起资源的争夺,需要增加各种锁,从而常常让并行处于等待状态;并发还会额外带来操作系统对线程调度切换的时间开销,增加Ws。不过,当一项任务中,Wp比Ws大得多,并且有多个CPU核心可供使用时,并行带来的性能提升是相当可观的。

好,回到nodejs上。我们设想一个计算场景:计算4000000内的质数数目。这个场景编程实现的时候,以除法运算为主,不涉及内存、对象等操作,理论上能够确保让nodejs以相对较快的速度运行,不会落后c太多,便于对比。

javascript寻找质数的方法已经在这篇博客中提供了,直接抄过来:

function zhishu_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;

        }

    }

    return true;

}

再写一个c语言版本的:

#include <math.h>

bool zhishu(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; } } return true; };

在nodejs中,我们用一个从1到4000000的循环来检索质数;c语言中,我们设置若干个线程,定义count为4000000,每个线程做如下操作要:如果count大于0,则取出count的值,并计算是否为质数,同时将count减1。根据这个思路,javascript版本的很容易写:

var count = 0;

for (j = 1; j < 4000000; j++) { if(zhishu(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_dirs": [

        "<!(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(&lock); num=count--; pthread_mutex_unlock(&lock); if(num>0){ if(zhishu(num))x++; }else{ break; } }while(true); std::cout<<' '<<x<<' '; pthread_exit(NULL); return null; }

在线程与线程之间,对于count这个变量是相互竞争的,我们需要确保同时只能有一个线程操作count变量。我们通过 pthread_mutex_t lock; 添加一个互斥锁。当执行 pthread_mutex_lock(&lock); 时,线程检查lock锁的情况,如果已锁定,则等待、重复检查,阻塞后续代码运行;如果锁已释放,则锁定,并执行后续代码。相应的, pthread_mutex_unlock(&lock); 就是解除锁状态。

由于编译器在编译的同时,进行编译优化,如果一个语句没有明确做什么事情,对其他语句的执行也没有影响时,会被编译器优化掉。在上面的代码中,我加入了统计质数数量的代码,如果不加的话,像这样的代码:

for (int j = 0; j < 4000000; j++) {

    zhishu(j);

}

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

添加addon的写法已经介绍过了,我们实现从javascript接收一个参数,表示线程数,然后在c中创建指定数量的线程完成质数检索。完整代码:

#include <nan.h>

#include <math.h>

#include <iostream>

#include "pthreadspthread.h"

#define MAX_THREAD 100

using namespace v8;

int count=4000000; pthread_t tid[MAX_THREAD]; pthread_mutex_t lock;

void *thread_p(void *null){ int num, x=0; do{ pthread_mutex_lock(&lock); num=count--; pthread_mutex_unlock(&lock); if(num>0){ if(zhishu(num))x++; }else{ break; } }while(true); std::cout<<' '<<x<<' '; pthread_exit(NULL); return null; }

NAN_METHOD(Zhishu){ NanScope(); pthread_mutex_init(&lock,NULL); double arg0=args[0]->NumberValue(); int c=0; for (int j = 0; j < arg0 && j<MAX_THREAD; j++) { pthread_create(&tid[j],NULL,thread_p,NULL); } for (int j = 0; j < arg0 && j<MAX_THREAD; j++) { pthread_join(tid[j],NULL); } NanReturnUndefined(); }

void Init(Handle<Object> exports){ exports->Set(NanSymbol("zhishu"), FunctionTemplate::New(Zhishu)->GetFunction()); }

NODE_MODULE(hello, Init);

phread_create可以创建线程,默认是joinable的,这个时候子线程受制于主线程;phread_join阻塞住主线程,等待子线程join,直到子线程退出。如果子线程已退出,则phread_join不会做任何事。所以对所有的线程都执行thread_join,可以保证所有的线程退出后才会例主线程继续进行。

完善一下nodejs脚本:

var zhishu_c=require('./build/Release/hello.node').zhishu;

function zhishu(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;

        }

    }

    return true;

}

console.time("c"); zhishu_c(100); console.timeEnd("c");

console.time("js"); var count=0; for (j = 1; j < 4000000; j++) { if(zhishu(j)){ count++; } } console.log(count); console.timeEnd("js");

看一下测试结果:

查看图片

单线程时,虽然C/C++的运行速度是nodejs的181%,但这个成绩我们认为在动态语言中,还是非常不错的。双线程时速度提升最明显,那是因为我的电脑是双核四线程CPU,这个时候已经可能在使用两个核心在进行处理。4线程时速度达到最大,此时应该是双核四线程能达到的极限,当线程再增加时,并不能再提升速度了。上述Amdahl定律中,p已达上限4。再增加线程,会增加操作系统进程调度的时间,增加锁的时间,尽管同时也能增加对CPU时间的竞争,但总体而言,Ws的增加更加明显,性能是下降的。如果在一台空闲的机器上做这个实验,数据应该会更好一点。

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

对于nodejs本身,的确是不擅长处理CPU密集的任务,但有了本文的经验,我想,想克服这个障碍,并非什么不可能的事情。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

nodejs中使用多线程编程的方法实例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

nodejs中使用多线程编程的方法实例

在以前的博文别说不可能,nodejs中实现sleep中,我向大家介绍了nodejs addon的用法。今天的主题还是addon,继续挖掘c/c++的能力,弥补nodejs的弱点。 我曾多次提到过nodejs的性能问题。其实就语言本身而言,n
2022-06-04

Linux系统下Shell多线程编程的实例用法

本篇内容主要讲解“Linux系统下Shell多线程编程的实例用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux系统下Shell多线程编程的实例用法”吧!#!/bin/bash#&mda
2023-06-13

Python多线程以及多线程中join()的使用方法

本篇内容主要讲解“Python多线程以及多线程中join()的使用方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python多线程以及多线程中join()的使用方法”吧!Python多线程与
2023-06-20

关于JAVA中多线程编程方法的详细解析(附实例)

一、程序、进程、线程程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码。它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文件。  从狭义来说,进程是正在运行的程序的实例;从广义上来说,进程
关于JAVA中多线程编程方法的详细解析(附实例)
2019-09-06

python中多进程和多线程的使用方法

这篇文章主要介绍了python中多进程和多线程的使用方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。进程和线程进程是系统进行资源分配的最小单位,线程是系统进行调度执行的最小
2023-06-14

python多线程线程锁的使用方法

小编给大家分享一下python多线程线程锁的使用方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!python的数据类型有哪些?python的数据类型:1. 数字
2023-06-14

如何使用Python中的多线程编程

如何使用Python中的多线程编程,需要具体代码示例引言:随着计算机技术的不断发展,多核处理器的普及以及大数据时代的到来,多线程编程变得越来越重要。多线程编程可以充分利用计算机的多个核心,加快程序的执行速度,提高系统的响应性能。Python
2023-10-22

Linux下的多线程编程实例解析

1 引言线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多
2022-06-03

在Java项目中实现多线程并发编程的方法

在Java项目中实现多线程并发编程的方法?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java 中的锁通常分为两种:通过关键字 synchronized 获取的
2023-05-31

C++ 多线程编程中线程池的应用

c++++ 多线程编程中使用线程池的好处包括:1)减少线程创建次数;2)负载均衡;3)避免资源争用。例如,通过使用线程池将图像转换任务分配给线程池,可以提高文件转换应用程序的转换速度。C++ 多线程编程中线程池的应用在现代 C++ 应用程
C++ 多线程编程中线程池的应用
2024-05-14

怎么使用PHP实现多线程编程

这篇文章主要介绍怎么使用PHP实现多线程编程,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!多线程线程首先说下线程:线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
2023-06-15

Python多进程并行编程实践中mpi4py的使用方法

这篇文章将为大家详细讲解有关Python多进程并行编程实践中mpi4py的使用方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前言在高性能计算的项目中我们通常都会使用效率更高的编译型的语言
2023-06-17

python 多线程实现多任务的方法示例

目录1 多线程实现多任务1.1 什么是线程?1.2 一个程序实现多任务的方法1.3 多线程的创建方式1.3.1 创建threading.Thread对象1.3.2 继承threading.Thread,并重写run1.4 线程何时开启,何时
2022-06-02

编程热搜

目录