3 回答
TA贡献1846条经验 获得超7个赞
在无缓冲通道中写入通道不会发生,直到必须有一些接收器等待接收数据,这意味着在下面的例子中
func main(){
ch := make(chan int)
ch <- 10 /* Main routine is Blocked, because there is no routine to receive the value */
<- ch
}
现在如果我们有其他 goroutine,同样的原则适用
func main(){
ch :=make(chan int)
go task(ch)
ch <-10
}
func task(ch chan int){
<- ch
}
这将起作用,因为任务例程正在等待数据被使用,然后写入发生到无缓冲通道。
为了更清楚,让我们交换主函数中第二条和第三条语句的顺序。
func main(){
ch := make(chan int)
ch <- 10 /*Blocked: No routine is waiting for the data to be consumed from the channel */
go task(ch)
}
这会导致死锁
所以简而言之,只有当有一些例程等待从通道读取时才会写入无缓冲通道,否则写入操作将被永远阻塞并导致死锁。
注意:相同的概念适用于缓冲通道,但在缓冲区已满之前不会阻止发送方,这意味着接收方不一定要与每个写操作同步。
因此,如果我们有大小为 1 的缓冲通道,那么您上面提到的代码将起作用
func main(){
ch := make(chan int, 1) /*channel of size 1 */
ch <-10 /* Not blocked: can put the value in channel buffer */
<- ch
}
但是如果我们给上面的例子写更多的值,那么就会发生死锁
func main(){
ch := make(chan int, 1) /*channel Buffer size 1 */
ch <- 10
ch <- 20 /*Blocked: Because Buffer size is already full and no one is waiting to recieve the Data from channel */
<- ch
<- ch
}
TA贡献1796条经验 获得超7个赞
在这个答案中,我将尝试解释错误消息,通过它我们可以稍微了解 go 在通道和 goroutines 方面的工作原理
第一个例子是:
package main
import "fmt"
func main() {
c := make(chan int)
c <- 1
fmt.Println(<-c)
}
错误信息是:
fatal error: all goroutines are asleep - deadlock!
在代码中,根本没有 goroutines(顺便说一句,这个错误是在运行时,而不是编译时)。当 go 运行此行时c <- 1,它希望确保通道中的消息将在某处(即<-c)收到。Go 不知道此时是否会收到频道。因此,go 将等待正在运行的 goroutine 完成,直到发生以下任一情况:
所有的 goroutine 都完成了(睡着了)
goroutine 之一尝试接收通道
在第 1 种情况下,go 会出错并显示上面的消息,因为现在 go 知道 goroutine 无法接收通道并且它需要一个。
在第 2 种情况下,程序将继续,因为现在知道收到了这个频道。这解释了 OP 示例中的成功案例。
- 3 回答
- 0 关注
- 231 浏览
添加回答
举报