ข้ามไปยังเนื้อหา

Goroutines

ใน TypeScript คุณมาร์ค function เป็น async แล้ว await ผลลัพธ์ ทุกครั้งที่เจอ await function จะหยุดพักและคืน control ให้ event loop แต่ทุกอย่างยังรันบน thread เดียว:

async function processUser(id: number) {
const user = await fetchUser(id);
return user;
}
// ต้อง await หรือ .then() เพื่อรอผล
await processUser(1);

ใน Go คุณเติม keyword go หน้า function call ใดก็ได้ call นั้นจะถูก dispatch เป็น goroutine — หน่วยทำงานน้ำหนักเบาที่รันอิสระ จัดการโดย Go runtime ไม่ต้องมี async ที่ตัว function และไม่ต้อง await ตอนเรียก:

go processUser(1) // รันในพื้นหลังทันที — ไม่ต้อง async keyword

จุดต่างที่สำคัญ: async function ของ JavaScript ยังรันบน thread เดียว แต่ goroutine รันแบบ parallel บน OS thread คนละตัวได้จริง

TypeScript
// TypeScript: async/await (single-threaded)
async function greet(name: string): Promise<void> {
console.log(`Hello from ${name}`);
}
// ต้อง await เพื่อรอผล
await greet("Alice");
await greet("Bob"); // รันตามลำดับ
// Promise.all เพื่อรันพร้อมกัน (แต่ยังคง single-threaded)
await Promise.all([greet("Alice"), greet("Bob")]);
Go
// Go: goroutines (truly concurrent)
package main
import (
"fmt"
"sync"
)
func greet(name string, wg *sync.WaitGroup) {
defer wg.Done() // แจ้ง WaitGroup เมื่อเสร็จ
fmt.Printf("Hello from %s\n", name)
}
func main() {
var wg sync.WaitGroup
names := []string{"Alice", "Bob", "Carol"}
for _, name := range names {
wg.Add(1) // ลงทะเบียนก่อน launch
go greet(name, &wg) // launch goroutine
}
wg.Wait() // block จนกว่าทุก goroutine เสร็จ
fmt.Println("All done!")
}

sync.WaitGroup เป็นเครื่องมือหลักของ Go สำหรับรอ goroutines กลุ่มหนึ่งให้เสร็จ ทำงานคล้าย Promise.all แต่ใช้ counter แทน array:

  1. wg.Add(n) — เพิ่ม counter ก่อน launch goroutine
  2. wg.Done() — ลด counter เมื่อ goroutine เสร็จ (เกือบทุกครั้งใช้คู่กับ defer)
  3. wg.Wait() — block จนกว่า counter จะเป็น 0

กฎ: เรียก wg.Add(1) ก่อน go f() เสมอ อย่าเรียกข้างใน goroutine เพราะ scheduler อาจไปถึง wg.Wait() ก่อนที่ goroutine จะเริ่มรันด้วยซ้ำ ทำให้ Wait คืนค่าทันทีทั้งที่งานยังค้างอยู่

เหมือน immediately-invoked arrow function ใน JS คุณ launch goroutine แบบ anonymous inline ได้เลย:

TypeScript
// TypeScript: immediately invoked async
(async () => {
const result = await doSomething();
console.log(result);
})();
Go
// Go: immediately launched goroutine
go func() {
result := doSomething()
fmt.Println(result)
}() // วงเล็บ () ด้านหลังเพื่อ invoke ทันที
package main
import (
"fmt"
"sync"
)
func printSquare(n int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("%d² = %d\n", n, n*n)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go printSquare(i, &wg)
}
wg.Wait()
fmt.Println("All squares printed")
}
คีย์เวิร์ดใดที่ใช้ launch goroutine ใน Go?
เมื่อไหร่ควรเรียก wg.Add(1)?
Goroutine stack เริ่มต้นมีขนาดประมาณเท่าไหร่?
method ใดของ WaitGroup ที่ใช้บอกว่า goroutine เสร็จแล้ว?