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

Channels

ใน JavaScript เมื่อคุณต้องการส่งผลลัพธ์จาก async operation ไปยังโค้ดอื่น คุณใช้ Promises หรือ callbacks:

function fetchUser(id: number): Promise<User> {
return new Promise((resolve) => {
// ... async work ...
resolve(user);
});
}
const user = await fetchUser(1); // await the Promise

ใน Go channels เป็น typed pipe ระดับ first-class สำหรับส่งค่าระหว่าง goroutines channel เป็นทั้งช่องทางสื่อสารและกลไก synchronization ในตัว:

ch := make(chan User) // create a channel for User values
go func() { ch <- user }() // send into the channel
user := <-ch // receive from the channel (blocks until a value arrives)
TypeScript
// TypeScript: Promise for a single future value
function getResult(): Promise<number> {
return new Promise(resolve => {
setTimeout(() => resolve(42), 100);
});
}
const result = await getResult();
console.log(result); // 42
Go
// Go: unbuffered channel — sender and receiver sync up
package main
import "fmt"
func getResult(ch chan<- int) {
ch <- 42 // send; blocks until someone receives
}
func main() {
ch := make(chan int) // unbuffered
go getResult(ch)
result := <-ch // receive; blocks until sender sends
fmt.Println(result) // 42
}

Buffered channel มี queue อยู่ภายใน sender จะไม่ block จนกว่า buffer จะเต็ม และ receiver จะไม่ block ตราบใดที่ buffer ยังมีค่าอยู่ ช่วยแยก producer ออกจาก consumer:

TypeScript
// TypeScript: simulate a buffer with an array
const queue: number[] = [];
function enqueue(val: number) {
queue.push(val); // does not block
}
enqueue(1); enqueue(2); enqueue(3);
// must drain it yourself
Go
// Go: buffered channel with a queue of 3
package main
import "fmt"
func main() {
ch := make(chan int, 3) // buffer capacity 3
ch <- 1 // does not block (space available)
ch <- 2
ch <- 3
// ch <- 4 // would block — buffer full
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
fmt.Println(<-ch) // 3
}

ใช้ for range ไล่อ่านค่าจาก channel จนกว่าจะถูก close ฝั่ง producer จะ close channel เพื่อบอกว่าส่งครบแล้ว คล้ายกับการ return ออกจาก async generator:

TypeScript
// TypeScript: async generator as an iterable stream
async function* generate() {
yield 1; yield 2; yield 3;
}
for await (const val of generate()) {
console.log(val);
}
Go
// Go: range over a channel closed by the producer
package main
import (
"fmt"
"sync"
)
func produce(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 5; i++ {
ch <- i
}
}
func main() {
ch := make(chan int, 5)
var wg sync.WaitGroup
wg.Add(1)
go produce(ch, &wg)
wg.Wait()
close(ch) // signal: no more values
for v := range ch { // drains until channel is closed
fmt.Println(v)
}
}
package main
import (
"fmt"
"sync"
)
func producer(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 5; i++ {
ch <- i
}
}
func main() {
ch := make(chan int, 5)
var wg sync.WaitGroup
wg.Add(1)
go producer(ch, &wg)
wg.Wait()
close(ch)
for v := range ch {
fmt.Println("Received:", v)
}
}
อะไรคือความแตกต่างระหว่าง unbuffered และ buffered channel?
syntax ใดที่ใช้รับค่าจาก channel?
ต้องทำอะไรก่อนใช้ for range บน channel?
chan<- int หมายความว่าอะไร?