SiamCafe · Blog
Worker Threads คืออะไร? สอนใช้ Multi-threading ใน Node.js สำหรับ CPU-intensive Tasks 2026
ฮาร์ดแวร์และคอมพิวเตอร์

Worker Threads คืออะไร? สอนใช้ Multi-threading ใน Node.js สำหรับ CPU-intensive Tasks 2026

เผยแพร่ May 28, 2026

Node.js ขึ้นชื่อเรื่องความเร็วในการจัดการ I/O-bound Tasks ด้วย Event Loop แบบ Single-threaded แต่เมื่อเจองานหนักที่ใช้ CPU มาก (CPU-intensive Tasks) เช่น การประมวลผลรูปภาพ การ Parse ข้อมูลขนาดใหญ่ หรือการคำนวณ Cryptography Event Loop จะถูก Block ทำให้ Server ไม่ตอบสนอง Worker Threads คือทางออกของปัญหานี้

ปัญหาของ Node.js Single Thread

Worker Threads คืออะไร? สอนใช้ Multi-threading ใน Node.js สำหรับ CPU-intensive Tasks 2026

Node.js ใช้ V8 JavaScript Engine ที่ทำงานบน Thread เดียว ซึ่งดีสำหรับ I/O Operations (อ่านไฟล์ เรียก API Query Database) เพราะ Node.js จะไม่รอ I/O แต่จะไปทำงานอื่นก่อนแล้วกลับมาเมื่อ I/O เสร็จ (Non-blocking I/O)

อ่านเพิ่ม: Elasticsearch OpenSearch Backup Recovery Strategy — คู่มือฉบ · อ่านเพิ่ม: BGP Routing Advanced Business Continuity — คู่มือฉบับสมบูรณ์ · อ่านเพิ่ม: BGP Routing Advanced Citizen Developer — คู่มือฉบับสมบูรณ์ 2

แต่ถ้ามีงาน CPU-intensive เช่น Loop คำนวณ 1 ล้านรอบ Event Loop จะถูก Block ทั้งหมด ไม่มีใครใช้งาน Server ได้จนกว่าจะคำนวณเสร็จ

// ตัวอย่าง: CPU-intensive task ที่ Block Event Loop
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// ถ้า n = 45 จะใช้เวลาหลายวินาที
// ระหว่างนั้น Server จะไม่ตอบสนองเลย!
app.get('/fibonacci', (req, res) => {
  const result = fibonacci(45); // Block Event Loop!
  res.json({ result });
});

Worker Threads คืออะไร?

Worker Threads คือ Module ในตัวของ Node.js (worker_threads) ที่ให้คุณสร้าง Thread ใหม่เพื่อรัน JavaScript Code แบบขนาน (Parallel) กับ Main Thread ทำให้งาน CPU-intensive ไม่ Block Event Loop

// main.js — สร้าง Worker
const { Worker } = require('worker_threads');

const worker = new Worker('./worker.js', {
  workerData: { n: 45 }
});

worker.on('message', (result) => {
  console.log('Fibonacci result:', result);
});

worker.on('error', (err) => {
  console.error('Worker error:', err);
});

worker.on('exit', (code) => {
  console.log('Worker exited with code:', code);
});
// worker.js — ทำงานใน Thread แยก
const { workerData, parentPort } = require('worker_threads');

function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

const result = fibonacci(workerData.n);
parentPort.postMessage(result); // ส่งผลกลับ Main Thread

การส่งข้อมูลระหว่าง Threads

1. postMessage (Structured Clone)

// Main Thread
worker.postMessage({ type: 'calculate', data: [1, 2, 3, 4, 5] });

// Worker Thread
parentPort.on('message', (msg) => {
  if (msg.type === 'calculate') {
    const sum = msg.data.reduce((a, b) => a + b, 0);
    parentPort.postMessage({ type: 'result', sum });
  }
});
หมายเหตุ: postMessage ใช้ Structured Clone Algorithm ซึ่ง Copy ข้อมูลทั้งหมด ถ้าข้อมูลใหญ่มากจะช้า ใช้ SharedArrayBuffer หรือ transferList แทน

2. SharedArrayBuffer — แชร์หน่วยความจำ

// Main Thread — สร้าง SharedArrayBuffer
const sharedBuffer = new SharedArrayBuffer(1024); // 1KB
const arr = new Int32Array(sharedBuffer);
arr[0] = 42;

const worker = new Worker('./worker.js', {
  workerData: { sharedBuffer }
});

// Worker Thread — อ่าน/เขียน SharedArrayBuffer ได้เลย
const { workerData } = require('worker_threads');
const arr = new Int32Array(workerData.sharedBuffer);
console.log(arr[0]); // 42
arr[1] = 100; // Main Thread จะเห็นค่านี้ด้วย

3. transferList — โอนย้ายข้อมูล (Zero-copy)

// Main Thread — Transfer ArrayBuffer (ไม่ copy, ย้ายเลย)
const buffer = new ArrayBuffer(1024);
const uint8 = new Uint8Array(buffer);
uint8[0] = 255;

worker.postMessage({ buffer }, [buffer]);
// buffer ใน Main Thread จะใช้ไม่ได้อีกต่อไป (transferred)

Worker Pool Pattern

การสร้าง Worker ใหม่ทุกครั้งมี Overhead ทางออกคือสร้าง Pool ของ Workers ที่พร้อมใช้งาน

ใช้ Library: piscina

// npm install piscina
const Piscina = require('piscina');

const pool = new Piscina({
  filename: './worker.js',
  maxThreads: 4, // จำนวน Worker สูงสุด
  minThreads: 2, // จำนวน Worker ขั้นต่ำ
});

// ใช้งาน — Pool จัดการให้อัตโนมัติ
async function processAll() {
  const results = await Promise.all([
    pool.run({ n: 40 }),
    pool.run({ n: 41 }),
    pool.run({ n: 42 }),
    pool.run({ n: 43 }),
  ]);
  console.log(results);
}
// worker.js สำหรับ piscina
module.exports = function({ n }) {
  function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
  return fibonacci(n);
};

ใช้ Library: workerpool

// npm install workerpool
const workerpool = require('workerpool');

const pool = workerpool.pool('./worker.js', {
  maxWorkers: 4,
});

pool.exec('fibonacci', [42])
  .then(result => console.log(result))
  .catch(err => console.error(err))
  .then(() => pool.terminate());

เมื่อไรใช้ Workers vs child_process vs cluster

Worker Threads คืออะไร? สอนใช้ Multi-threading ใน Node.js สำหรับ CPU-intensive Tasks 2026
FeatureWorker Threadschild_processcluster
แชร์หน่วยความจำได้ (SharedArrayBuffer)ไม่ได้ไม่ได้
Overheadต่ำสูง (Process ใหม่)สูง (Process ใหม่)
Use CaseCPU-intensive ใน Node.jsรัน Script/Program ภายนอกScale HTTP Server หลาย Core
CommunicationpostMessage + SharedArrayBufferIPC (stdin/stdout/message)IPC (message)
Isolationแชร์ Process (Thread-level)แยก Process สมบูรณ์แยก Process สมบูรณ์
เมื่อไรใช้คำนวณหนัก ภายใน Node.jsรัน Python, FFmpeg, etc.Scale Web Server หลาย CPU

Use Cases จริง

1. Image Processing

// worker-image.js
const { parentPort, workerData } = require('worker_threads');
const sharp = require('sharp');

async function processImage() {
  const { inputPath, outputPath, width, height } = workerData;
  await sharp(inputPath)
    .resize(width, height)
    .jpeg({ quality: 80 })
    .toFile(outputPath);
  parentPort.postMessage({ status: 'done', outputPath });
}

processImage();

2. Data Parsing (CSV/JSON)

// แบ่ง File ขนาดใหญ่ให้แต่ละ Worker Parse
const { Worker } = require('worker_threads');

function parseChunk(chunk, workerId) {
  return new Promise((resolve, reject) => {
    const w = new Worker('./parse-worker.js', {
      workerData: { chunk, workerId }
    });
    w.on('message', resolve);
    w.on('error', reject);
  });
}

// Main: แบ่ง data เป็น chunks แล้วส่งแต่ละ Worker
const chunks = splitIntoChunks(bigData, 4);
const results = await Promise.all(
  chunks.map((chunk, i) => parseChunk(chunk, i))
);
const merged = results.flat();

3. Crypto Operations

// worker-hash.js
const { parentPort, workerData } = require('worker_threads');
const crypto = require('crypto');

const hash = crypto.pbkdf2Sync(
  workerData.password,
  workerData.salt,
  100000, // iterations
  64,
  'sha512'
);

parentPort.postMessage(hash.toString('hex'));

Worker Threads + Express

const express = require('express');
const Piscina = require('piscina');

const app = express();
const pool = new Piscina({
  filename: './heavy-computation.js',
  maxThreads: 4,
});

app.get('/compute/:n', async (req, res) => {
  try {
    const result = await pool.run({ n: parseInt(req.params.n) });
    res.json({ result });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Event Loop ยังตอบสนอง Request อื่น ๆ ได้ตามปกติ!
app.get('/health', (req, res) => {
  res.json({ status: 'ok' }); // ไม่ถูก Block
});

app.listen(3000);

Benchmarks: Single Thread vs Worker Threads

TaskSingle Thread4 WorkersSpeedup
Fibonacci(42) x 4~12 sec~3.5 sec3.4x
Image Resize 100 images~30 sec~8 sec3.75x
CSV Parse 500MB~20 sec~6 sec3.3x
PBKDF2 Hash x 100~15 sec~4 sec3.75x

Common Mistakes

  1. สร้าง Worker ใหม่ทุก Request: Overhead สูงมาก ใช้ Worker Pool แทน
  2. ส่งข้อมูลใหญ่ผ่าน postMessage: ใช้ SharedArrayBuffer หรือ transferList
  3. ใช้ Worker สำหรับ I/O Tasks: ไม่จำเป็น Node.js จัดการ I/O ได้ดีอยู่แล้ว
  4. ไม่จัดการ Error ใน Worker: Worker crash = ไม่มี response ต้อง handle error event
  5. สร้าง Worker มากเกินจำนวน CPU Core: ไม่ได้เร็วขึ้น อาจช้าลงด้วยซ้ำ
  6. ลืม Terminate Worker: Memory leak ถ้าไม่ terminate worker เมื่อเสร็จงาน

Alternatives: Bun Workers & Deno Workers

RuntimeAPIข้อดี
Node.jsworker_threads moduleMature, Ecosystem ใหญ่, SharedArrayBuffer
BunWeb Workers API (new Worker)เร็วกว่า Node.js 2-4x, API ง่ายกว่า
DenoWeb Workers APISecure by default, TypeScript built-in

สรุป

Worker Threads เป็นเครื่องมือสำคัญสำหรับ Node.js Developer ที่ต้องจัดการ CPU-intensive Tasks ช่วยให้ Event Loop ไม่ถูก Block ทำให้ Server ยังคงตอบสนองได้ดี ใช้ Worker Pool Library อย่าง piscina เพื่อจัดการ Workers อย่างมีประสิทธิภาพ และจำไว้ว่า Worker Threads เหมาะสำหรับ CPU-bound Tasks เท่านั้น ไม่ใช่ I/O-bound Tasks