2014-08-31 74 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个进程,则可能会锁定浪费时间在应用程序空间之外的线程上下文之间不断切换。