nodejs - 我发现多线程或使用多个进程比单个进程慢。为什么?

时间:2014-08-31 16:48:02

标签: multithreading node.js performance express web-worker

我有一个CPU密集型任务(循环一些数据并评估结果)。我想为这些使用多个内核,但我的性能始终比仅使用单个内核更糟糕。

我试过了:

  • 使用express在不同端口上创建多个进程并将任务发送到这些进程
  • 使用webworker-threads使用线程池
  • 在不同的线程中运行任务

我通过计算我可以完成的迭代总数来计算结果,然后除以我处理问题所花费的时间。使用单核时,我的结果明显更好。

一些兴趣点:

  • 我可以确定何时只使用一个核心以及何时通过任务管理器使用多个核心。我正在使用预期的核心数。
  • 我有很多ram
  • 我试过只运行2或3个核心
  • 我添加了nextTicks,在这种情况下似乎不会影响任何事情
  • 这些任务需要几秒钟,所以我不觉得自己在开销上损失惨重

知道这里发生了什么事吗?

线程更新:我怀疑webworker-threads中存在错误 现在跳过快递,我认为这个问题可能与我的线程循环有关。我正在做的是创建一个线程,然后尝试连续运行它们,但在它们之间来回发送数据。即使两个线程都在耗尽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(&#39; start&#39; + thread.id,function(){...})。这不起作用,因为在我执行tp.all.emit(&#39; start&#39; + result.threadId,...)的结果中,消息没有被提取。< / p>

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

之后再也没有发生过。

多个快递服务器的更新:我获得了改进但是比预期的要小

我重新审视了这个解决方案并获得了更多运气。我认为我的原始测量可能存在缺陷。新结果:

  • 单个过程:3.3次迭代/秒
  • 主要流程+ 2台服务器:4.2次迭代/秒
  • 主进程+3台服务器:4.9次迭代/秒

我觉得有点奇怪的是,我没有看到2台服务器大约6次迭代/秒,9次3次。我知道网络有一些损失,但如果我增加任务时间是足够高,我认为网络损失应该很小。

1 个答案:

答案 0 :(得分:1)

您不应该推动Node.js进程运行多个线程以提高性能。在四核处理器上运行,有1个express进程处理一般请求和3个express进程处理CPU密集型请求可能是最有效的设置,这就是为什么我建议你尝试设计您的express进程以推迟使用Web worker并简单地阻塞直到它们产生结果。这将使您按照设计运行单个线程的单个进程,最有可能产生最佳结果。

我不知道Web worker包如何处理同步的复杂性,影响c空间中发生的Node.js的I / O线程池等,但我相信你一般都想要介绍Web工作人员能够同时管理更多阻塞任务,而严重影响其他不需要线程和系统I / O的请求,否则可以方便地响应。这并不一定意味着应用此项将为正在执行的特定任务产生改进的性能。如果您运行4个进程,其中包含4个执行I / O的线程,您可能会将自己锁定在浪费时间在应用程序空间外的线程上下文之间不断切换。