node.js - 是否可以使用 Node 工作线程来执行数据库插入?

标签 node.js node-cluster worker-thread import-module node-worker-threads

我最近阅读了 Node 的“worker_threads”模块,它允许在多个线程中并行执行 Javascript 代码,这对于 CPU 密集型操作很有用。 (注意:这些不是 Chrome 在浏览器中制作的网络 worker )
我正在构建一个功能,我需要在不阻塞浏览器的情况下执行大量 Postgres INSERT。
问题是:在我实例化 worker 的 Javascript 文件中,我不允许导入任何内容,包括本地 Node 模块或 NPM 库(如 Knex.js),这是执行数据库查询所必需的。我收到一条错误消息:不能在模块外使用 import 语句 文件一执行。
我尝试将工作代码放在另一个文件中,并在顶部使用 import 语句(同样的错误)。我尝试将 Knex 对象提供给 workerData,但它无法克隆非本地 JS 对象。
我没有想法 - 如果我们无法导入任何 NPM 库,有谁知道如何在工作线程中与数据库交互?!?!

// mainThread.js

const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

import knex from 'knex'; // --> *** UNCAUGHT EXCEPTION: Cannot use import statement outside a module ***

if (isMainThread) {
  module.exports = async function runWorker (rowsToInsert = []) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, { workerData: { rowsToInsert } });

      worker.on('message', (returningRows) => resolve(returningRows));
      worker.on('error', reject);
      worker.on('exit', (code) => {
        if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`));
      });
    });
  };
} else {
  const { rowsToInsert } = workerData;

  return knex('table').insert(rowsToInsert)
    .then((returningRows) => {
      parentPort.postMessage({ data: returningRows });
    });
}
我正在关注此网页上的教程:https://blog.logrocket.com/use-cases-for-node-workers/

最佳答案

这当然是可能的,但这是一个非常糟糕的主意。
数据库驱动程序已经是异步且非阻塞的 JavaScript 线程。按照您的建议将您的插入调用移动到一个单独的线程不仅不会让您获得任何性能提升,而且实际上会降低整体性能,因为线程间通信涉及的开销:

  • 同步和消息传递不是免费的
  • JavaScript 使用 structured cloning在线程之间移动数据时。这意味着您所有的rowsToInsert必须复制,这是(相对)昂贵的。

  • 通常,真正适合使用 JS 线程的唯一时间是当您的 JavaScript 代码执行 CPU 密集型工作时。 node docs say as much right at the top :

    Workers (threads) are useful for performing CPU-intensive JavaScript operations. They will not help much with I/O-intensive work. Node.js’s built-in asynchronous I/O operations are more efficient than Workers can be.


    这意味着如果您正在执行大量解析、数学或类似操作,则可能适合在线程中完成工作。然而,简单地将数据从一个地方铲到另一个地方(即,I/O)并不是线程的理想选择——毕竟, Node 的设计被调整为在这种工作中高效。
    你不说你的rowsToInsert来自,但如果它来自 HTTP 请求,则使用线程是错误的。但是,如果您在服务器上解析例如 CSV 或 JSON 文件,那么在线程中执行此操作可能是值得的,但线程完成所有工作很重要(因此内存不需要在线程之间移动)。您发布给工作人员的消息应该只是“处理位于/foo/bar.csv 的文件”,然后工作线程完成其余的工作。

    你得到的错误是 the same that you'd get without worker threads : 你正在尝试使用 import在常规的非模块 JS 文件中。将工作文件重命名为 *.mjs 或使用 require('knex')反而。
    Node 的ES module documentation详细介绍 import不同于 require .

    关于node.js - 是否可以使用 Node 工作线程来执行数据库插入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62924613/

    相关文章:

    node.js - 在electron应用中,当我使用worker_thread时,使用Command+Q退出应用后出现异常

    javascript - 如何在Web工作线程中使用javascript变量

    node.js - 使用 Octopus Deploy 在 Ubuntu 上运行 npm install

    javascript - 使用promise模块连接mongodb时出错

    node.js - 提高 Node JS 服务器应用程序吞吐量的步骤

    node.js - PM2 集群模式与 Node 集群性能

    c++ - Boost 线程特定存储问题 (boost/thread/tss.hpp)

    node.js - 我无法用 npm 更新 electron

    javascript - (教程)由于 SyntaxError : Block-scoped declarations,脚本无法运行

    node.js - 在 NodeJS 中使用集群时无法获取工作 block 中的所有工作人员