1 回答
![?](http://img1.sycdn.imooc.com/533e4d660001312002000200-100-100.jpg)
TA贡献1820条经验 获得超9个赞
如果您愿意,您可以将频道视为一种邮箱(可能具有特殊的传送能力,例如游戏 Portal中的门户)。
无缓冲通道是一个完全没有空间容纳任何包裹的邮箱。对于要邮寄包裹(发送价值)的人来说,他们必须等到收件人的手从邮箱中伸出来。然后,他们可以将包裹放入手中,手将退回邮箱,并带走包裹。如果有其他人在排队,您必须在其他人后面排队。
缓冲通道是一个可以容纳一个或多个包的邮箱。要发送包裹,请排队(如果有的话)。当你到达队伍的最前面时,你可以看看这个盒子。如果有空间容纳您的包裹,您可以将其放入并继续处理您的事务。如果没有,您可以等到有空间,然后将包裹放入并继续处理您的业务。
所以有一个通用的发送模式:
如果有必要的话就排队吧。
当您到达队列的头部时,如果有空间,请将包裹放入,否则等待空间,或者,对于无缓冲的通道,等待有人来到另一侧(接收)并把手伸进去接收。
同时,如果您想从某个通道接收数据,则需要排队,就像发送一样。一旦你排在队伍的最前面,你就可以从盒子里取出一个包裹,或者——对于无缓冲的通道——把你的手伸出盒子的另一边,等待有人拿走。过来并在里面放一些东西。
在这个类比中,每个 goroutine 就像一个人,或者一个Go gopher。如果需要,它(或他或她或您喜欢的任何代词)可以排队,并将东西放入这些通道之一或将其从这些通道之一中取出。你的程序从一个 goroutine 开始,它调用main
.
在您的代码中,您派生出第二个 goroutine,它从 开始multiplyByTwo
。这个 goroutine 等待一次,等待一个数字出现在通道中,或者在本例中,等待某人发送一个数字,因为通道没有缓冲。然后它将得到的(单个)数字加倍,打印结果,然后退出/死亡/被埋葬,永远不再存在。
同时,您main
等待某人接收(这将是您的第二个 goroutine),直到它准备好接受3
中的数字n
。那部分成功了。然后你main
等待另一个接收,以便它可以发送常量3
。
当你main
等待的时候,你的另一个 goroutine 正在做它的工作——或者可能已经完成它的工作——然后退出。现在,整个系统中只有一个“人”(或地鼠或其他什么),等待着第二个人——这个人不存在,也永远不会出生——来取号。底层 Go 系统可以判断该事件永远不会发生,此时您会收到消息:
fatal error: all goroutines are asleep - deadlock!
(这也会终止程序)。
这引入了一个新问题:如何告诉第二个 goroutine 不再有数字到来?答案是您可以关闭通道,使用close
.
如果我们坚持用邮箱进行类比,您可以将关闭通道视为在通道的发送端放置特殊的贴纸或标签。这可以防止任何人进一步输入值。通道中的任何包裹都已经是安全的——它们会一直留在那里,直到有人收到它们——但没有新的包裹可以进入。在接收方,很容易区分包裹和这个特殊贴纸之间的区别:所以当您遇到“关闭”标签,您知道不会有更多的值出现。如果频道没有缓冲,您可以立即看到此贴纸。如果它是缓冲的,您必须先取出所有现有的包,然后才能看到它。
一般来说,发送者应该关闭通道,以便接收者知道他们不会从中得到任何东西。(在许多特定情况下,您可以在不关闭通道的情况下逃脱。特别是,如果正在运行的 goroutinemain
从其对 的调用返回main
,则所有其他 goroutine 或多或少会立即死亡。)
请注意,一旦关闭,任何发送者都无法再次关闭该通道,因此这意味着,如果您有多个发送者共享的单个通道,则只有其中一个可以关闭该通道!使这一工作正常进行是很棘手的,因此更常见的是避免像这样在多个 write-goroutine 之间共享一个通道。
- 1 回答
- 0 关注
- 88 浏览
添加回答
举报