Back to list
dev_to 2026年3月21日

Node.js の Worker Threads: どのタイミングで、どのように使用するか

Worker Threads in Node.js: When and How to Use Them

Translated: 2026/3/21 8:01:33
nodejsworker-threadsasync-programmingmulti-threadingbackend-engineering

Japanese Translation

Node.js の Worker Threads: どのタイミングで、どのように使用するか あなたの API がパスワードのハッシュ化を実行し、イベントループがブロックされます。他のすべてのリクエストが待機します。Node は単スレッドですが、そうせむ必要はありません。CPU 绑定的タスク(ハッシュ化、画像処理、大規模ペイロードの JSON 解析、圧縮)はイベントループをブロックします。Node がこれらのタスクを処理している間は、入ってくるリクエスト、タイマー、I/O キューバックを処理できません。 ```javascript import { Worker, isMainThread, parentPort, workerData } from "worker_threads"; if (isMainThread) { const worker = new Worker(__filename, { workerData: { input: "heavy-task" } }); worker.on("message", (result) => console.log("Result:", result)); worker.on("error", (err) => console.error("Worker error:", err)); } else { // これは別のスレッドで実行されます const result = heavyComputation(workerData.input); parentPort?.postMessage(result); } ``` ご依頼ごとに新しいワーカーを作成するのは高コストです。プール化してください: ```javascript import { Worker } from "worker_threads"; import os from "os"; class WorkerPool { private workers: Worker[] = []; private queue: Array<{ data: unknown; resolve: Function; reject: Function }> = []; private available: Worker[] = []; constructor(script: string, size = os.cpus().length) { for (let i = 0; i < size; i++) { const w = new Worker(script); this.workers.push(w); this.available.push(w); } } run(data: unknown): Promise { return new Promise((resolve, reject) => { const worker = this.available.pop(); if (!worker) { this.queue.push({ data, resolve, reject }); return; } worker.once("message", (result) => { this.available.push(worker); const next = this.queue.shift(); if (next) { this.run(next.data) .then(next.resolve, next.reject); } resolve(result); }); worker.postMessage(data); }); } } ``` はい:パスワードハッシュ化、画像/ビデオ処理、CSV 解析、圧縮、暗号化、CPU 集約的な検証。 いいえ:データベースクエリ、HTTP 要求、ファイル I/O。これらはすでに非同期かつ非ブロッキングです。Worker Threads を使うとオーバーヘッドがかかりながら恩恵を得られません。大規模データの場合、`postMessage`はデータをコピーします。メモリをコピーせずにスレッド間で共有するには `SharedArrayBuffer` を使用し、同期には `Atomics` を使用してください。 Worker Threads を I/O に使用する際:データベース呼び出しはすでに非ブロッキングです。ご依頼ごとのワーカー作成:生成コストが高いため、プールの使用を推奨します。ワーカークラッシュの処理:エラーと終了イベントを常に監視してください。多数のワーカー:CPU コアの数を超過するとコンテキストスイッチングのオーバーヘッドが生じます。 本稿は「Production Backend Patterns」シリーズの一部です。より実践的なバックエンドエンジニアリングの概要をご覧いただくためにフォローしてください。

Original Content

Worker Threads in Node.js: When and How to Use Them Your API hashes a password. The event loop blocks. Every other request waits. Node is single-threaded, but it does not have to be. CPU-bound work (hashing, image processing, JSON parsing large payloads, compression) blocks the event loop. While Node processes that work, it cannot handle incoming requests, timers, or I/O callbacks. import { Worker, isMainThread, parentPort, workerData } from "worker_threads"; if (isMainThread) { const worker = new Worker(__filename, { workerData: { input: "heavy-task" } }); worker.on("message", (result) => console.log("Result:", result)); worker.on("error", (err) => console.error("Worker error:", err)); } else { // This runs in a separate thread const result = heavyComputation(workerData.input); parentPort?.postMessage(result); } Creating a new worker per request is expensive. Pool them: import { Worker } from "worker_threads"; import os from "os"; class WorkerPool { private workers: Worker[] = []; private queue: Array<{ data: unknown; resolve: Function; reject: Function }> = []; private available: Worker[] = []; constructor(script: string, size = os.cpus().length) { for (let i = 0; i < size; i++) { const w = new Worker(script); this.workers.push(w); this.available.push(w); } } run(data: unknown): Promise { return new Promise((resolve, reject) => { const worker = this.available.pop(); if (\!worker) { this.queue.push({ data, resolve, reject }); return; } worker.once("message", (result) => { this.available.push(worker); const next = this.queue.shift(); if (next) this.run(next.data).then(next.resolve, next.reject); resolve(result); }); worker.postMessage(data); }); } } Yes: Password hashing, image/video processing, CSV parsing, compression, encryption, CPU-intensive validation. No: Database queries, HTTP requests, file I/O. These are already async and non-blocking. Worker threads add overhead without benefit. For large data, postMessage copies the data. Use SharedArrayBuffer to share memory between threads without copying. Use Atomics for synchronization. Using workers for I/O: Database calls are already non-blocking Creating a worker per request: Spawning is expensive, use a pool Not handling worker crashes: Always listen for error and exit events Too many workers: More workers than CPU cores causes context switching overhead Part of my Production Backend Patterns series. Follow for more practical backend engineering.