Select
Promise.race vs Select
หัวข้อที่มีชื่อว่า “Promise.race vs Select”ใน TypeScript Promise.race รับ array ของ Promise และ resolve ด้วยตัวที่เสร็จก่อน:
const result = await Promise.race([ fetch('/api/primary'), fetch('/api/backup'),]);ใน Go select ทำแบบเดียวกันนี้กับ channels — รอหลาย channel operation พร้อมกัน แล้วทำงานกับตัวแรกที่พร้อม:
select {case msg := <-ch1: fmt.Println("from ch1:", msg)case msg := <-ch2: fmt.Println("from ch2:", msg)}select จะ block จนกว่าจะมีอย่างน้อยหนึ่ง case ที่ทำงานได้ ถ้าหลาย case พร้อมในจังหวะเดียวกัน Go จะสุ่มเลือกแบบ uniform — scheduling จึงยุติธรรมแต่ไม่ deterministic
Select Statement พื้นฐาน
หัวข้อที่มีชื่อว่า “Select Statement พื้นฐาน”// TypeScript: Promise.raceasync function withTimeout<T>( promise: Promise<T>, ms: number): Promise<T> { const timeout = new Promise<never>((_, reject) => setTimeout(() => reject(new Error("timeout")), ms) ); return Promise.race([promise, timeout]);}// Go: select สำหรับเลือก channel แรกที่พร้อมpackage main
import "fmt"
func main() { ch1 := make(chan string, 1) ch2 := make(chan string, 1)
ch1 <- "one" ch2 <- "two"
// รับจาก ch1 ก่อน (deterministic เพราะใช้ select แยก) select { case msg := <-ch1: fmt.Println("Received from ch1:", msg) } select { case msg := <-ch2: fmt.Println("Received from ch2:", msg) }}Default Case — Non-blocking Select
หัวข้อที่มีชื่อว่า “Default Case — Non-blocking Select”เพิ่ม branch default เพื่อให้ select คืนค่าทันทีเมื่อไม่มี channel ไหนพร้อม แทนที่จะ block:
// TypeScript: non-blocking check ด้วย Promiseasync function tryReceive(): Promise<string | null> { const result = await Promise.race([ getMessage(), Promise.resolve(null), // fallback ทันที ]); return result;}// Go: non-blocking select ด้วย defaultpackage main
import "fmt"
func main() { ch := make(chan string, 1)
select { case msg := <-ch: fmt.Println("Got:", msg) default: fmt.Println("No message available") // รันทันที }
ch <- "hello"
select { case msg := <-ch: fmt.Println("Got:", msg) default: fmt.Println("No message available") }}Select กับ Context Cancellation
หัวข้อที่มีชื่อว่า “Select กับ Context Cancellation”การใช้ select ที่พบบ่อยที่สุดในงานจริงคือฟังทั้งงานที่เข้ามาและ cancellation signal จาก context.Context ไปพร้อมกัน:
// TypeScript: AbortController สำหรับ cancellationasync function processWithAbort(signal: AbortSignal) { for (const item of items) { if (signal.aborted) break; await processItem(item); }}// Go: select กับ ctx.Done() สำหรับ cancellationpackage main
import ( "context" "fmt" "sync")
func worker(ctx context.Context, jobs <-chan int, wg *sync.WaitGroup) { defer wg.Done() for { select { case j, ok := <-jobs: if !ok { return // channel ถูก close } fmt.Println("Processing job:", j) case <-ctx.Done(): fmt.Println("Worker cancelled") return } }}package main
import "fmt"
func main() { ch1 := make(chan string, 1) ch2 := make(chan string, 1)
ch1 <- "hello" ch2 <- "world"
// รับจาก ch1 ก่อน select { case msg := <-ch1: fmt.Println("ch1:", msg) }
// รับจาก ch2 select { case msg := <-ch2: fmt.Println("ch2:", msg) }
// default case: non-blocking select { case msg := <-ch1: fmt.Println("extra:", msg) default: fmt.Println("no more messages") }}Loading Go runtime (first run only, ~8 MB)…