2014-08-31 75 views
5

我有一個CPU密集型任務(循環通過一些數據和評估結果)。我想利用多個內核來實現這些功能,但是我的性能始終比使用單個內核差。nodejs - 我發現多線程或使用多個進程比單個進程慢。爲什麼?

我已經試過:

  • 創建不同端口上的多個進程與express和使用線程池
發送任務,這些過程
  • 使用webworker-threads運行在不同的線程任務

    我測量的結果是通過計算我可以完成的迭代總次數併除以我花在解決問題上的時間量。當使用單核時,我的結果明顯更好。

    一些興趣點:

    • 我時,我只用一個核心,當我通過任務管理器使用多個內核識別。我正在使用預期數量的內核。
    • 我有很多的RAM
    • 我試着運行在只有2或3芯
    • 我加入這似乎並不在此情況下影響什麼nextTicks
    • 任務需要幾秒鐘每次我這樣不覺得我失去了很多開銷

    有什麼想法,這是怎麼回事?

    更新線程:我懷疑一個錯誤webworker線程 現在跳過快遞,我認爲這個問題可能與我的線程循環做。我正在做的是創建一個線程,然後試圖連續運行它們,但在它們之間來回發送數據。即使兩個線程正在使用CPU,只有線程0返回值。我的假設通常最終會散發給那些空閒時間最長的線程,但似乎並非如此。我設立看起來像這樣

    在threadtask.js

    thread.on('init', function() { 
    
        thread.emit('ready'); 
    
        thread.on('start', function(data) { 
         console.log("THREAD " + thread.id + ": execute task"); 
         //... 
         console.log("THREAD " + thread.id + ": emit result"); 
         thread.emit('result', otherData)); 
        }); 
    }); 
    

    main.js

    var tp = Threads.createPool(NUM_THREADS); 
    tp.load(threadtaskjsFilePath); 
    var readyCount = 0; 
    tp.on('ready', function() { 
        readyCount++; 
    
        if(readyCount == tp.totalThreads()) { 
         console.log('MAIN: Sending first start event'); 
         tp.all.emit('start', JSON.stringify(data)); 
        } 
    }); 
    
    tp.on('result', function(eresult) { 
        var result = JSON.parse(eresult); 
        console.log('MAIN: result from thread ' + result.threadId); 
        //... 
        console.log('MAIN: emit start' + result.threadId); 
        tp.any.emit('start' + result.threadId, data); 
    }); 
    
    tp.all.emit("init", JSON.stringify(data2)); 
    

    輸出到這場災難

    MAIN: Sending first start event 
    THREAD 0: execute task 
    THREAD 1: execute task 
    THREAD 1: emit result 
    MAIN: result from thread 1 
    THREAD 0: emit result 
    THREAD 0: execute task 
    THREAD 0: emit result 
    MAIN: result from thread 0 
    MAIN: result from thread 0 
    THREAD 0: execute task 
    THREAD 0: emit result 
    THREAD 0: execute task 
    THREAD 0: emit result 
    MAIN: result from thread 0 
    MAIN: result from thread 0 
    THREAD 0: execute task 
    THREAD 0: emit result 
    THREAD 0: execute task 
    THREAD 0: emit result 
    MAIN: result from thread 0 
    MAIN: result from thread 0 
    

    我曾嘗試另一種方法也是如此在那裏我會發射所有,但是然後讓每個線程監聽只有它可以回答的消息。例如,thread.on('start'+ thread.id,function(){...})。這是行不通的,因爲在做tp.all.emit('start'+ result.threadId,...)的結果時,消息不會被拾取。

    MAIN: Sending first start event 
    THREAD 0: execute task 
    THREAD 1: execute task 
    THREAD 1: emit result 
    THREAD 0: emit result 
    

    之後沒有更多的事情發生。

    更新多個Express服務器:我得到改進,但比預期的

    我重新審視這個解決方案,並有更多的運氣更小。我認爲我的原始測量可能有缺陷。新的結果:

    • 單進程:3.3迭代/第二
    • 主要工藝+ 2級的服務器:4.2迭代/第二
    • 主要工藝+ 3級的服務器:4.9迭代/第二

    一件事我發現有點奇怪的是,我沒有看到2臺服務器每秒6次迭代,3次9次。我知道網絡存在一些損失,但如果我將任務時間增加到足夠高,網絡損失應該相當輕微我會想。

  • +1

    你確定你是CPU綁定,而不是IO綁定? – 2014-08-31 16:55:18

    +0

    相當確定。你知道我怎麼能確認它不是io綁定的嗎?線程初始化後,我不從磁盤加載任何東西。我發送一些json數組來回線程,但它們並不龐大。 – i8abug 2014-08-31 16:57:19

    +0

    關注磁盤/網絡使用情況,看看它是否看起來像你最大的缺陷 – 2014-08-31 16:58:56

    回答

    1

    您不應該推動您的Node.js進程運行多個線程以提高性能。在四核處理器上運行,有1 express進程處理一般請求和3 express進程處理CPU密集型請求可能是最有效的設置,這就是爲什麼我建議您嘗試設計express進程以推遲使用網絡工作者,只是阻止,直到他們產生結果。這將使您按照設計使用單個線程運行單個進程,最有可能產生最佳結果。

    我不知道Web工作包如何處理同步,影響發生在c空間等中的Node.js的I/O線程池,但我相信您通常會想要介紹Web工作人員以便能夠同時管理更多的阻塞任務,而不會影響不需要線程和系統I/O的其他請求,或者可以以其他方式方便地響應其他請求。這並不一定意味着應用這將爲正在執行的特定任務產生改進的性能。如果使用4個執行I/O的線程運行4個進程,則可能會鎖定浪費時間在應用程序空間之外的線程上下文之間不斷切換。