การดู : 0

12/04/2026 18:16น.

JS2GO EP.42 Goroutine Pools และ Worker Pools ใน Go และ JavaScript

JS2GO EP.42 Goroutine Pools และ Worker Pools ใน Go และ JavaScript

#JavaScript

#Go

#Concurrency

#Worker Pool

#Goroutine Pool

ควบคุมจำนวนงานพร้อมกันอย่างมีประสิทธิภาพ ป้องกัน resource leak และออกแบบระบบให้รองรับโหลดระดับหมื่นคำขอ/วินาที 🚀

 

เมื่อระบบต้องประมวลผลงานจำนวนมากพร้อมกัน เช่น

  • ประมวลผลภาพ/วิดีโอ
  • คำนวณหนัก (CPU-intensive)
  • ส่งอีเมลครั้งละหลายพันรายการ
  • ประมวลผล background jobs
  • ทำ data processing จาก queue

 

ถ้าปล่อยให้ Goroutine หรือ Worker ถูกสร้างขึ้น “ไม่จำกัดจำนวน” → ระบบจะล่มทันทีจาก:

  • 🧨 memory พุ่งจน Out Of Memory
  • 🧨 CPU 100% ค้างยาว
  • 🧨 routine/thread หลักหมื่นจน OS สลับ context หนักมาก
  • 🧨 latency พุ่งสูงผิดปกติ
  • 🧨 API endpoint ตอบช้า/ล่มทั้งระบบ

 

Solution คือ → “Pool”

Pool ทำหน้าที่ควบคุมว่า “รอบนี้ให้รันงานได้สูงสุดกี่งานเท่านั้น”

ส่วน Queue คือที่เก็บงานที่รอคิวเข้ามาใน Pool

 

⭐ 1. ทำไมระบบต้องใช้ “Pool”?

 

ถ้าไม่มี pool → ระบบจะเกิดปัญหานี้ทันที:

ปัญหาผลกระทบ
เปิด Goroutine / Worker มากเกินไปMemory leak
CPU สลับ context หนักเกินlatency สูงขึ้นเรื่อย ๆ
Thread มากเกิน OS รับไม่ไหวServer crash
งานค้างใน backgrounduptime ต่ำ, queue overflow

 

Pool ทำหน้าที่เป็น “ตัวควบคุมทรัพยากรระดับระบบ” เพื่อให้ระบบเสถียรแม้มี load สูงระดับหมื่นหรือแสนงานต่อวินาที

 

⭐ 2. Goroutine Pool ใน Go

 

Go มี Goroutine ขนาดเล็ก (~2KB stack) และสร้างเร็วมาก แต่หากสร้างเป็นหมื่น/แสนก็ยังล่มได้เหมือนกัน หากไม่จำกัดจำนวน

 

🧪 ตัวอย่าง Goroutine Pool (แบบ Production-friendly)

package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
	defer wg.Done()
	for j := range jobs {
		time.Sleep(200 * time.Millisecond) // จำลองงานหนัก
		results <- j * 2
		fmt.Println("Worker", id, "processed job", j)
	}
}

func main() {
	jobs := make(chan int, 10)
	results := make(chan int, 10)

	var wg sync.WaitGroup

	// สร้าง Pool = 3 workers
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go worker(i, jobs, results, &wg)
	}

	// ส่งงานเข้า queue
	for j := 1; j <= 9; j++ {
		jobs <- j
	}
	close(jobs)

	wg.Wait()
	close(results)

	for r := range results {
		fmt.Println("Result:", r)
	}
}

 

✔ จุดเด่นของ Goroutine Pool

  • เบาและเร็วมาก รองรับงานพร้อมกันจำนวนมหาศาล
  • channels คล้าย queue ทำให้ flow ปลอดภัย ไม่ race
  • ไม่ต้องสร้าง/ทำลาย thread จำนวนมาก
  • latency ต่ำมากในงาน CPU-bound หรือ pipeline processing

 

✔ เหมาะกับ

  • Data pipeline
  • CPU-heavy batch processing
  • Message queue consumers
  • File processing
  • WebSocket Broadcasting

 

⭐ 3. Worker Pool ใน JavaScript (Node.js)

 

Node.js เป็น single-threaded แต่สามารถทำงานแบบ multi-thread ได้ผ่าน worker_threads

 

🧪 Worker Pool แบบใช้งานได้จริง

 

worker.js

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

function heavyTask(num) {
  return num * 2;
}

parentPort.postMessage(heavyTask(workerData));

 

main.js

const { Worker } = require('worker_threads');

function runWorker(num) {
  return new Promise((resolve, reject) => {
    const worker = new Worker('./worker.js', { workerData: num });

    worker.on('message', resolve);
    worker.on('error', reject);
  });
}

async function main() {
  const tasks = [1, 2, 3, 4, 5];
  const results = await Promise.all(tasks.map(t => runWorker(t)));
  console.log(results);
}

main();

 

✔ จุดเด่นของ Worker Pool

  • ใช้ CPU ได้หลาย core
  • ทำงาน CPU-heavy ได้จริง
  • แยก process จาก main thread ทำให้ลด event loop lag

 

✔ เหมาะกับ

  • Image resizing
  • Video transcoding
  • Big JSON parsing
  • Encryption / hashing
  • AI model inference

 

⭐ 4. เปรียบเทียบความสามารถ Go vs JavaScript

 

ความสามารถGo (Goroutine Pool)JavaScript (Worker Pool)
ความเร็ว⭐⭐⭐⭐⭐⭐⭐⭐
ใช้หลาย CPU core⭐⭐⭐⭐⭐⭐⭐⭐
Memory footprintต่ำมากปานกลาง
ง่ายต่อการเขียนง่ายและกระชับซับซ้อนกว่า
Scalingสูงมาก (10k+ routines)ปานกลาง
ใช้กับงานแบบconcurrent-heavyCPU-heavy

 

สรุปสั้น ๆ:
🔥 Go → ทำงาน CPU/Concurrent หนักมากได้แบบ native
🔥 JS → ดีมากสำหรับ I/O-heavy และ CPU งานกลาง–หนักผ่าน worker threads

 

⭐ 5. Best Practices สำหรับระบบ Production

 

✔ 1) จำกัดจำนวน workers/goroutines

  • Go → ใช้ buffered channel
  • JS → จำกัด worker ตามจำนวน CPU core (4–8 ตัวเหมาะสมสุด)

 

✔ 2) ใส่ timeout เสมอ

ห้ามปล่อย network call ค้าง → เกิด zombie worker

 

✔ 3) Implement Graceful Shutdown

ต้องปิดสิ่งเหล่านี้ให้ครบ:

  • workers
  • goroutines
  • channels
  • file handles
  • queues

 

✔ 4) Monitoring worker health

ป้องกัน worker ค้างโดยไม่ตอบ (silent failure)

 

✔ 5) ใช้ Queue system ถ้า load สูงมาก

เช่น

  • Redis Streams
  • RabbitMQ
  • Kafka

เพื่อกระจาย load และทำ retry logic

 


 

⭐ 6. สรุปท้ายบท

 

Goroutine Pool (Go) และ Worker Pool (JavaScript) คือแกนสำคัญของระบบที่ต้องรองรับงานจำนวนมากในเวลาเดียวกัน ทั้งสองภาษาออกแบบแตกต่างกัน แต่ให้ผลลัพธ์ที่ยอดเยี่ยมเมื่อใช้ถูกงาน

 

ถ้างานของคุณคือ:

  • CPU-heavy
  • data pipeline
  • real-time streaming
  • backend ที่ต้อง uptime สูง

👉 Go คือคำตอบที่ดีที่สุด

 

ถ้างานของคุณคือ:

  • API-first
  • I/O-bound
  • real-time web
  • ทำงานร่วมกับ frontend ecosystem

👉 JavaScript คือทางเลือกที่ยอดเยี่ยม

 

🔵 EP.43 ตอนต่อไป

การทำ Rate Limiting และ Throttling ใน Go และ Node.js

พร้อมตัวอย่างโค้ด Production ของ:

  • Token Bucket
  • Leaky Bucket
  • Sliding Window
  • Middleware ใน Go + Node.js

เพื่อปกป้องระบบของคุณจากการยิง request จำนวนมากแบบอยู่รอดได้จริงในระบบ Production 🚀