1 回答
TA贡献1895条经验 获得超3个赞
在后台,两个 goroutine 仍然继续循环并相互发送值。
不,他们没有。
当您使用 制作频道时make(chan *Ball)
,您正在制作一个无缓冲的频道。这相当于说make(chan *Ball,0)
,这意味着通道可以在其中容纳 0 个东西 - 或者更明确地说,对通道的任何写入都将阻塞,直到另一个例程从通道读取,反之亦然。
无缓冲通道的执行顺序是这样的:
玩家“ping”创建,尝试从表中读取
ball := <-table
,阻塞直到table
被写入玩家“pong”创建,尝试从表中读取
ball := <-table
,阻塞直到table
被写入Main
table
使用以下行将Ball 写入:table <- new(Ball) // game on; toss the ball
这不会被阻止,因为有人正在等待在频道上阅读。
现在 ping 读取球(在 ping 之后继续执行
ball := <-table
)Ping 把球放在桌子上
table <- ball
,没有被挡住,因为 pong 正在等待Pong 读球(在 pong 之后继续执行
ball := <-table
)Pong 把球放在桌子上
table <- ball
,没有被挡住,因为 ping 正在等待ping 读球(ping 后继续执行
ball := <-table
)....等等
直到主要通过阅读球而不是其中一名球员来结束比赛
这是使用通道确保一次只运行一个例程的一个很好的示例。
为了结束游戏,主线程在一秒钟后简单地将球抢出通道:
time.Sleep(1 * time.Second) fmt.Println(<-table) // game over; grab the ball
在此之后,table
通道将是空的,任何进一步的读取都会被阻塞。
此时,两个
player
例程都被阻塞在ball := <- table
。
如果您<-table
在主线程中进一步读取,该读取也将阻塞,直到例程尝试写入表通道。但是,由于没有其他例程在运行,因此会出现死锁(所有 goroutine 都被阻塞)。
行。那么我可以在通道中放两个球吗?
不。
如果我们尝试在通道中放入两个球,我们可能会得到输出:
Ping 1Pong 1
因为这两个player
例程都会在试图将球放回通道时被卡住 - 但没有人会试图阅读它。订单如下所示:
玩家“ping”创建,尝试从表中读取,被阻止
玩家“pong”创建,尝试从表中读取,被阻止
main 将第一个球放入
table
(未阻塞,因为有人在等待阅读)main 将第二个球放入
table
(没有被阻塞,因为有人在等待阅读)平读第一个球
庞读第二个球
Ping 把第一个球放在桌子上,因为没有人在等待阅读而被阻止
Pong 把第二个球放在桌子上,因为没人等着看,所以被挡住了
两名球员都被封锁
直到主要通过读取两个球来结束游戏。
正如评论者指出的那样,结束游戏的更好做法是关闭频道。但是,我希望这次讨论能消除您的困惑。
- 1 回答
- 0 关注
- 171 浏览
添加回答
举报