【问题标题】:nodejs - I'm finding multithreading or using multiple processes is slower than a single process. Why?nodejs - 我发现多线程或使用多个进程比单个进程慢。为什么?
【发布时间】:2014-08-31 16:48:01
【问题描述】:

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

我试过了:

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

我通过计算我可以完成的迭代总数并除以我解决问题所花费的时间来衡量结果。使用单核时,我的结果明显更好。

一些兴趣点:

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

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

线程更新:我怀疑 webworker-threads 中存在错误 现在跳过快递,我认为这个问题可能与我的线程循环有关。我正在做的是创建一个线程,然后尝试连续运行它们,但在它们之间来回发送数据。即使两个线程都在使用 CPU,但只有线程 0 正在返回值。我的假设是 emit any 通常最终会将消息发送到空闲时间最长的线程,但似乎并非如此。我的设置是这样的

在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

在那之后没有任何事情发生。

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

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

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

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

【问题讨论】:

  • 你确定你是cpu bound而不是io bound吗?
  • 相当肯定。你知道我如何确认它不是 io 绑定的吗?线程初始化后,我没有从磁盘加载任何内容。我正在向线程来回发送一些 json 数组,但它们并不大。
  • 密切关注磁盘/网络的使用情况,看看您是否已经用尽了
  • @i8abug 你确定你不是从那些工作线程中的磁盘或网络读取数据吗?
  • 如何使用express 创建多个进程?通常你可以在同一个进程的不同端口上创建多个服务器。

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


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-02
    • 2013-06-08
    • 2015-07-09
    • 2014-07-21
    • 2019-01-26
    • 2021-12-14
    • 1970-01-01
    • 2016-04-07
    相关资源
    最近更新 更多