最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

nodejs中使用多線程編程的方法實例

 更新時間:2015年03月24日 10:16:41   投稿:junjie  
這篇文章主要介紹了nodejs中使用多線程編程的方法實例,本文使用nodejs addon借助c/c++的能力擴展nodejs多線程編程,需要的朋友可以參考下

在以前的博文別說不可能,nodejs中實現(xiàn)sleep中,我向大家介紹了nodejs addon的用法。今天的主題還是addon,繼續(xù)挖掘c/c++的能力,彌補nodejs的弱點。

我曾多次提到過nodejs的性能問題。其實就語言本身而言,nodejs的性能還是很高的,雖然不及大多部靜態(tài)語言,但差距也并不大;相對其他動態(tài)語言而言,速度優(yōu)勢非常明顯。但為什么我們常常說nodejs不能勝任CPU密集型場景呢?因為由于其單線程特性,對于CPU密集型場景,它并不能充分利用CPU。計算機科學中有一個著名的Amdahl定律:

假設(shè)總工作量W,可以分解為兩個部分:只能串行計算的Ws和允許并行計算的Wp。那么,在p個CPU并行計算的情況下,性能上能夠帶來speedup倍的提升。Amdahl定律描述了并行能做到的和不能做到的。它是一種理想情況,實際情況會復雜得多。比如并發(fā)很可能會引起資源的爭奪,需要增加各種鎖,從而常常讓并行處于等待狀態(tài);并發(fā)還會額外帶來操作系統(tǒng)對線程調(diào)度切換的時間開銷,增加Ws。不過,當一項任務(wù)中,Wp比Ws大得多,并且有多個CPU核心可供使用時,并行帶來的性能提升是相當可觀的。

好,回到nodejs上。我們設(shè)想一個計算場景:計算4000000內(nèi)的質(zhì)數(shù)數(shù)目。這個場景編程實現(xiàn)的時候,以除法運算為主,不涉及內(nèi)存、對象等操作,理論上能夠確保讓nodejs以相對較快的速度運行,不會落后c太多,便于對比。

javascript尋找質(zhì)數(shù)的方法已經(jīng)在這篇博客中提供了,直接抄過來:

復制代碼 代碼如下:

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的循環(huán)來檢索質(zhì)數(shù);c語言中,我們設(shè)置若干個線程,定義count為4000000,每個線程做如下操作要:如果count大于0,則取出count的值,并計算是否為質(zhì)數(shù),同時將count減1。根據(jù)這個思路,javascript版本的很容易寫:

復制代碼 代碼如下:

var count = 0;

for (j = 1; j < 4000000; j++) {
    if(zhishu(j)){
        count++;
    }
}


關(guān)鍵難點就是c語言的多線程編程。早期c/c++并沒有考慮并行計算的需求,所以標準庫中并沒有提供多線程支持。而不同的操作系統(tǒng)通常實現(xiàn)也是有區(qū)別的。為了避免這種麻煩,我們采用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中l(wèi)ib和include目錄的引用,并且不出現(xiàn)依賴問題,那是最好的,就沒有必要用我的方法來做。

那么接下來就進入C/C++多線程的一切了,定義一個線程處理函數(shù):

復制代碼 代碼如下:

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; 添加一個互斥鎖。當執(zhí)行 pthread_mutex_lock(&lock); 時,線程檢查lock鎖的情況,如果已鎖定,則等待、重復檢查,阻塞后續(xù)代碼運行;如果鎖已釋放,則鎖定,并執(zhí)行后續(xù)代碼。相應(yīng)的, pthread_mutex_unlock(&lock); 就是解除鎖狀態(tài)。

由于編譯器在編譯的同時,進行編譯優(yōu)化,如果一個語句沒有明確做什么事情,對其他語句的執(zhí)行也沒有影響時,會被編譯器優(yōu)化掉。在上面的代碼中,我加入了統(tǒng)計質(zhì)數(shù)數(shù)量的代碼,如果不加的話,像這樣的代碼:

復制代碼 代碼如下:

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

 是會直接被編譯器跳過的,實際不會運行。

添加addon的寫法已經(jīng)介紹過了,我們實現(xiàn)從javascript接收一個參數(shù),表示線程數(shù),然后在c中創(chuàng)建指定數(shù)量的線程完成質(zhì)數(shù)檢索。完整代碼:

復制代碼 代碼如下:

#include <nan.h>
#include <math.h>
#include <iostream>
#include "pthreads\pthread.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可以創(chuàng)建線程,默認是joinable的,這個時候子線程受制于主線程;phread_join阻塞住主線程,等待子線程join,直到子線程退出。如果子線程已退出,則phread_join不會做任何事。所以對所有的線程都執(zhí)行thread_join,可以保證所有的線程退出后才會例主線程繼續(xù)進行。

完善一下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");

 看一下測試結(jié)果:

 單線程時,雖然C/C++的運行速度是nodejs的181%,但這個成績我們認為在動態(tài)語言中,還是非常不錯的。雙線程時速度提升最明顯,那是因為我的電腦是雙核四線程CPU,這個時候已經(jīng)可能在使用兩個核心在進行處理。4線程時速度達到最大,此時應(yīng)該是雙核四線程能達到的極限,當線程再增加時,并不能再提升速度了。上述Amdahl定律中,p已達上限4。再增加線程,會增加操作系統(tǒng)進程調(diào)度的時間,增加鎖的時間,盡管同時也能增加對CPU時間的競爭,但總體而言,Ws的增加更加明顯,性能是下降的。如果在一臺空閑的機器上做這個實驗,數(shù)據(jù)應(yīng)該會更好一點。

從這個實驗中,我們可以得出這樣的結(jié)論,對于CPU密集型的運算,交給靜態(tài)語言去做,效率會提高很多,如果計算中較多涉及內(nèi)存、字符串、數(shù)組、遞歸等操作(以后再驗證),性能提升更為驚人。同時,合理地利用多線程能有效地提高處理效率,但并不是線程越多越好,要根據(jù)機器的情況合理配置。

對于nodejs本身,的確是不擅長處理CPU密集的任務(wù),但有了本文的經(jīng)驗,我想,想克服這個障礙,并非什么不可能的事情。

相關(guān)文章

  • 使用基于Node.js的構(gòu)建工具Grunt來發(fā)布ASP.NET MVC項目

    使用基于Node.js的構(gòu)建工具Grunt來發(fā)布ASP.NET MVC項目

    這篇文章主要介紹了使用基于Node.js的構(gòu)建工具Grunt來發(fā)布ASP.NET MVC項目的教程,自動化構(gòu)建工具Grunt具有編譯壓縮單元測試等功能,十分強大,需要的朋友可以參考下
    2016-02-02
  • Node.js Mongodb 密碼特殊字符 @的解決方法

    Node.js Mongodb 密碼特殊字符 @的解決方法

    在去年的 DB 勒索事件之后, 不少的同學開始加強 Mongodb 的安全性, 其中一種辦法就是設(shè)置復雜的密碼. 那么如果設(shè)置的密碼里包含一些如 “@”, “:” 一樣的特殊字符,怎么處理呢?下面小編給大家?guī)砹薔ode.js Mongodb 密碼特殊字符 @的解決方法,一起學習吧
    2017-04-04
  • Node.js簡單入門前傳

    Node.js簡單入門前傳

    Node.js 是一個基于Chrome JavaScript 運行時建立的一個平臺。接下來通過本文給大家分享node.js 入門前傳,感興趣的朋友一起看看吧
    2017-08-08
  • 基于nodejs使用express創(chuàng)建web服務(wù)器的操作步驟

    基于nodejs使用express創(chuàng)建web服務(wù)器的操作步驟

    express實際上是對nodejs內(nèi)置http進行封裝后的第三方包,其中提供了快捷創(chuàng)建web服務(wù)器以及處理請求路由的方法,使我們可以更加方便快捷的實現(xiàn)一個web服務(wù)器項目,本文件給大家詳細介紹基于nodejs使用express?創(chuàng)建web服務(wù)器的操作步驟
    2023-07-07
  • express啟用https使用小記

    express啟用https使用小記

    這篇文章主要介紹了express啟用https使用小記,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • Node.js中readline模塊實現(xiàn)終端輸入

    Node.js中readline模塊實現(xiàn)終端輸入

    本文主要介紹了Node.js中readline模塊實現(xiàn)終端輸入,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • nvm如何切換與管理node版本

    nvm如何切換與管理node版本

    這篇文章主要介紹了nvm如何切換與管理node版本問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Node.js應(yīng)用設(shè)置安全的沙箱環(huán)境

    Node.js應(yīng)用設(shè)置安全的沙箱環(huán)境

    這篇文章主要介紹了Node.js應(yīng)用設(shè)置安全的沙箱環(huán)境的方法以及注意事項,對此有需要的朋友可以參考學習下。
    2018-04-04
  • npm?install的--save和--save-dev使用說明(推薦)

    npm?install的--save和--save-dev使用說明(推薦)

    這篇文章主要介紹了npm?install的--save和--save-dev使用說明,文中給大家提到了各個命令的區(qū)別及各種安裝參數(shù)的區(qū)別,需要的朋友可以參考下
    2022-08-08
  • node.js 微信開發(fā)之定時獲取access_token

    node.js 微信開發(fā)之定時獲取access_token

    本文給大家分享的是在使用node.js做微信開發(fā)的過程中如何定時獲取access_token的方法,有需要的小伙伴可以參考下
    2020-02-02

最新評論

靖州| 江门市| 巴中市| 乐业县| 香格里拉县| 额济纳旗| 尚义县| 大同县| 海丰县| 南城县| 崇礼县| 金乡县| 贡山| 巨野县| 旬邑县| 额济纳旗| 松滋市| 彭阳县| 嫩江县| 禄劝| 永新县| 昆明市| 宣武区| 南岸区| 金塔县| 天长市| 腾冲县| 鄂伦春自治旗| 油尖旺区| 昔阳县| 长兴县| 枣阳市| 汕头市| 布拖县| 噶尔县| 荃湾区| 吉木乃县| 固安县| 岫岩| 曲水县| 桂阳县|