在 Go 中,通道(channel)会在以下情况下阻塞:
1. 发送操作阻塞
-
无缓冲通道: 当你向无缓冲通道发送数据时,如果没有其他 goroutine 读取数据,发送操作将阻塞。
ch := make(chan int) // 无缓冲通道 ch <- 1 // 阻塞,直到有接收者
-
缓冲通道已满: 当缓冲通道的缓冲区已满时,尝试发送数据将阻塞,直到有空间可用。
ch := make(chan int, 2) // 缓冲通道,大小为 2 ch <- 1 ch <- 2 // ch <- 3 // 阻塞,直到有人接收
2. 接收操作阻塞
-
无缓冲通道: 当你从无缓冲通道接收数据时,如果没有其他 goroutine 发送数据,接收操作将阻塞。
ch := make(chan int) // 无缓冲通道 val := <-ch // 阻塞,直到有人发送
-
缓冲通道为空: 当尝试从缓冲通道接收数据时,如果通道为空,接收操作将阻塞,直到有数据可用。
ch := make(chan int, 2) // 缓冲通道 // ch <- 1 // val := <-ch // 阻塞,直到有人发送数据
3. select 语句阻塞
-
select
会阻塞,直到其中一个 case 可执行。如果所有的 case 都不可执行(例如,所有的通道都没有数据可读或没有空间可写),则select
将阻塞。select { case msg := <-ch1: // 如果 ch1 没有数据则阻塞 fmt.Println(msg) case ch2 <- 2: // 如果 ch2 满则阻塞 fmt.Println("Sent to ch2") }
4. 避免阻塞
-
使用
default
: 在select
中添加default
分支可以避免阻塞。select { case msg := <-ch: fmt.Println(msg) default: fmt.Println("No messages received") }
总结
通道的阻塞机制是 Go 实现并发的重要特性,它确保了数据的安全传递和同步。在使用通道时,理解何时会阻塞对于编写高效的并发程序至关重要。