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

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

TypeScript
// TypeScript: Promise.race
async 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
// 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)
}
}

เพิ่ม branch default เพื่อให้ select คืนค่าทันทีเมื่อไม่มี channel ไหนพร้อม แทนที่จะ block:

TypeScript
// TypeScript: non-blocking check ด้วย Promise
async function tryReceive(): Promise<string | null> {
const result = await Promise.race([
getMessage(),
Promise.resolve(null), // fallback ทันที
]);
return result;
}
Go
// Go: non-blocking select ด้วย default
package 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 ที่พบบ่อยที่สุดในงานจริงคือฟังทั้งงานที่เข้ามาและ cancellation signal จาก context.Context ไปพร้อมกัน:

TypeScript
// TypeScript: AbortController สำหรับ cancellation
async function processWithAbort(signal: AbortSignal) {
for (const item of items) {
if (signal.aborted) break;
await processItem(item);
}
}
Go
// Go: select กับ ctx.Done() สำหรับ cancellation
package 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")
}
}
select statement ใน Go เปรียบเทียบกับอะไรใน JavaScript?
เมื่อหลาย case พร้อมในเวลาเดียวกัน select จะทำอย่างไร?
default case ใน select ทำให้เกิดอะไร?