Goroutines
Async Functions vs Goroutines
หัวข้อที่มีชื่อว่า “Async Functions vs Goroutines”ใน TypeScript คุณมาร์ค function เป็น async แล้ว await ผลลัพธ์ ทุกครั้งที่เจอ await function จะหยุดพักและคืน control ให้ event loop แต่ทุกอย่างยังรันบน thread เดียว:
async function processUser(id: number) { const user = await fetchUser(id); return user;}await processUser(1); // you must await or .then() to consume itใน Go คุณเติม keyword go หน้า function call ใดก็ได้ call นั้นจะถูก dispatch เป็น goroutine — หน่วยทำงานน้ำหนักเบาที่รันอิสระ จัดการโดย Go runtime ไม่ต้องมี async ที่ตัว function และไม่ต้อง await ตอนเรียก:
go processUser(1) // fires immediately in the backgroundจุดต่างที่สำคัญ: async function ของ JavaScript ยังรันบน thread เดียว แต่ goroutine รันแบบ parallel บน OS thread คนละตัวได้จริง
การสร้าง Goroutines
หัวข้อที่มีชื่อว่า “การสร้าง Goroutines”// TypeScript: async/await (single-threaded event loop)async function greet(name: string): Promise<void> { console.log("Hello from " + name);}
// sequentialawait greet("Alice");await greet("Bob");
// concurrent (still one thread, interleaved via event loop)await Promise.all([greet("Alice"), greet("Bob")]);// Go: goroutines (truly concurrent)package main
import ( "fmt" "sync")
func greet(name string, wg *sync.WaitGroup) { defer wg.Done() // signal WaitGroup when done 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) // register before launching go greet(name, &wg) // launch goroutine }
wg.Wait() // block until all goroutines finish fmt.Println("All done!")}sync.WaitGroup — รอ Goroutines ให้เสร็จ
หัวข้อที่มีชื่อว่า “sync.WaitGroup — รอ Goroutines ให้เสร็จ”sync.WaitGroup เป็นเครื่องมือหลักของ Go สำหรับรอ goroutines กลุ่มหนึ่งให้เสร็จ ทำงานคล้าย Promise.all แต่ใช้ counter แทน array:
wg.Add(n)— เพิ่ม counter ก่อน launch goroutinewg.Done()— ลด counter เมื่อ goroutine เสร็จ (เกือบทุกครั้งใช้คู่กับdefer)wg.Wait()— block จนกว่า counter จะเป็น 0
กฎ: เรียก
wg.Add(1)ก่อนgo f()เสมอ อย่าเรียกข้างใน goroutine เพราะ scheduler อาจไปถึงwg.Wait()ก่อนที่ goroutine จะเริ่มรันด้วยซ้ำ ทำให้Waitคืนค่าทันทีทั้งที่งานยังค้างอยู่
wg.Go — Add, go และ Done ในคำสั่งเดียว (Go 1.25+)
หัวข้อที่มีชื่อว่า “wg.Go — Add, go และ Done ในคำสั่งเดียว (Go 1.25+)”กฎ “Add ก่อน go” พลาดง่าย Go 1.25 จึงเพิ่ม WaitGroup.Go ที่ทำ Add(1) launch goroutine และเรียก Done ให้เมื่อ function return — รูปทรงตอนนี้อ่านแทบเหมือน Promise.all บน list ของ async call:
// TypeScriptawait Promise.all(urls.map(async (url) => { await fetchOne(url);}));// Go 1.25+var wg sync.WaitGroupfor _, url := range urls { wg.Go(func() { fetchOne(url) }) // Add(1) + go + Done, handled for you}wg.Wait()โค้ดใหม่ให้ใช้ wg.Go ส่วน wg.Add(1) / defer wg.Done() ยังเจอในโค้ดเบสส่วนใหญ่ (และตัวอย่างบางส่วนด้านล่าง) และตอนนี้ go vet จะเตือนถ้าวาง Add ไว้ข้างใน goroutine
Anonymous Goroutines
หัวข้อที่มีชื่อว่า “Anonymous Goroutines”เหมือน immediately-invoked arrow function ใน JS คุณ launch goroutine แบบ anonymous inline ได้เลย:
// TypeScript: immediately invoked async(async () => { const result = await doSomething(); console.log(result);})();// Go: immediately launched anonymous goroutinego func() { result := doSomething() fmt.Println(result)}() // trailing () invokes the function literal immediatelypackage 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")}Compiling on go.dev (Go 1.27)… offline? an in-browser runtime (~8 MB, Go 1.26) is used instead