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

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 for the first result
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 picks the first ready channel
package main
import "fmt"
func main() {
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch1 <- "one"
ch2 <- "two"
// Use separate selects so output is deterministic
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 via Promise.race with null fallback
async function tryReceive(): Promise<string | null> {
return Promise.race([
getMessage(),
Promise.resolve(null), // resolves immediately
]);
}
Go
// Go: non-blocking select with 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") // runs immediately
}
ch <- "hello"
select {
case msg := <-ch:
fmt.Println("Got:", msg)
default:
fmt.Println("No message available")
}
}

การใช้ select ที่พบบ่อยที่สุดในงานจริงคือฟังทั้งงานที่เข้ามาและ cancellation signal จาก context.Context ไปพร้อมกัน:

TypeScript
// TypeScript: AbortController for cooperative cancellation
async function processItems(
items: string[],
signal: AbortSignal
) {
for (const item of items) {
if (signal.aborted) break;
await processItem(item);
}
}
Go
// Go: select listening to both a jobs channel and ctx.Done()
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 was closed — no more work
}
fmt.Println("Processing job:", j)
case <-ctx.Done():
fmt.Println("Worker cancelled:", ctx.Err())
return
}
}
}
package main
import "fmt"
func main() {
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch1 <- "hello"
ch2 <- "world"
// Receive from ch1 first (deterministic: separate selects)
select {
case msg := <-ch1:
fmt.Println("ch1:", msg)
}
// Receive from ch2
select {
case msg := <-ch2:
fmt.Println("ch2:", msg)
}
// default: non-blocking — ch1 is empty now
select {
case msg := <-ch1:
fmt.Println("extra:", msg)
default:
fmt.Println("no more messages")
}
}
select statement ใน Go เปรียบเทียบกับอะไรใน JavaScript?
เมื่อหลาย case พร้อมในเวลาเดียวกัน select จะทำอย่างไร?
default case ใน select ทำให้เกิดอะไร?