{"id":15446,"date":"2024-11-18T18:03:30","date_gmt":"2024-11-18T10:03:30","guid":{"rendered":"https:\/\/fwq.ai\/blog\/?p=15446"},"modified":"2024-11-18T18:03:30","modified_gmt":"2024-11-18T10:03:30","slug":"%e5%a6%82%e4%bd%95%e4%bc%98%e9%9b%85%e5%9c%b0%e5%85%b3%e9%97%adgo-channel","status":"publish","type":"post","link":"https:\/\/fwq.ai\/blog\/15446\/","title":{"rendered":"\u5982\u4f55\u4f18\u96c5\u5730\u5173\u95edGo channel"},"content":{"rendered":"<p>\u51e0\u5929\u524d\uff0c\u6211\u5199\u4e86\u4e00\u7bc7\u6587\u7ae0\u6765\u8bf4\u660egolang\u4e2dchannel\u7684\u4f7f\u7528\u89c4\u8303\u3002\u5728reddit\u548cHN\uff0c\u90a3\u7bc7\u6587\u7ae0\u6536\u5230\u4e86\u5f88\u591a\u8d5e\u540c\uff0c\u4f46\u662f\u6211\u4e5f\u6536\u5230\u4e86\u4e0b\u9762\u51e0\u4e2a\u5173\u4e8eGo channel\u8bbe\u8ba1\u548c\u89c4\u8303\u7684\u6279\u8bc4\uff1a<\/p>\n<ol>\n<li>\u5728\u4e0d\u80fd\u66f4\u6539channel\u72b6\u6001\u7684\u60c5\u51b5\u4e0b\uff0c\u6ca1\u6709\u7b80\u5355\u666e\u904d\u7684\u65b9\u5f0f\u6765\u68c0\u67e5channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u4e86<\/li>\n<li>\u5173\u95ed\u5df2\u7ecf\u5173\u95ed\u7684channel\u4f1a\u5bfc\u81f4panic\uff0c\u6240\u4ee5\u5728closer(\u5173\u95ed\u8005)\u4e0d\u77e5\u9053channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u7684\u60c5\u51b5\u4e0b\u53bb\u5173\u95edchannel\u662f\u5f88\u5371\u9669\u7684<\/li>\n<li>\u53d1\u9001\u503c\u5230\u5df2\u7ecf\u5173\u95ed\u7684channel\u4f1a\u5bfc\u81f4panic\uff0c\u6240\u4ee5\u5982\u679csender(\u53d1\u9001\u8005)\u5728\u4e0d\u77e5\u9053channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u7684\u60c5\u51b5\u4e0b\u53bb\u5411channel\u53d1\u9001\u503c\u662f\u5f88\u5371\u9669\u7684<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>\u90a3\u4e9b\u6279\u8bc4\u770b\u8d77\u6765\u90fd\u5f88\u6709\u9053\u7406\uff08\u5b9e\u9645\u4e0a\u5e76\u6ca1\u6709\uff09\u3002\u662f\u7684\uff0c\u6ca1\u6709\u4e00\u4e2a\u5185\u7f6e\u51fd\u6570\u53ef\u4ee5\u68c0\u67e5\u4e00\u4e2achannel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u3002\u5982\u679c\u4f60\u80fd\u786e\u5b9a\u4e0d\u4f1a\u5411channel\u53d1\u9001\u4efb\u4f55\u503c\uff0c\u90a3\u4e48\u4e5f\u786e\u5b9e\u9700\u8981\u4e00\u4e2a\u7b80\u5355\u7684\u65b9\u6cd5\u6765\u68c0\u67e5channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\uff1a<\/p>\n<pre>package main\r\n\r\nimport \"fmt\"\r\n\r\ntype T int\r\n\r\nfunc IsClosed(ch &lt;-chan T) bool {\r\n\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0 case &lt;-ch:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return true\r\n\u00a0\u00a0\u00a0 default:\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 return false\r\n}\r\n\r\nfunc main() {\r\n\u00a0\u00a0\u00a0 c := make(chan T)\r\n\u00a0\u00a0\u00a0 fmt.Println(IsClosed(c)) \/\/ false\r\n\u00a0\u00a0\u00a0 close(c)\r\n\u00a0\u00a0\u00a0 fmt.Println(IsClosed(c)) \/\/ true\r\n}<\/pre>\n<p>\u4e0a\u9762\u5df2\u7ecf\u63d0\u5230\u4e86\uff0c\u6ca1\u6709\u4e00\u79cd\u9002\u7528\u7684\u65b9\u5f0f\u6765\u68c0\u67e5channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u4e86\u3002\u4f46\u662f\uff0c\u5c31\u7b97\u6709\u4e00\u4e2a\u7b80\u5355\u7684 closed(chan T) bool\u51fd\u6570\u6765\u68c0\u67e5channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\uff0c\u5b83\u7684\u7528\u5904\u8fd8\u662f\u5f88\u6709\u9650\u7684\uff0c\u5c31\u50cf\u5185\u7f6e\u7684len\u51fd\u6570\u7528\u6765\u68c0\u67e5\u7f13\u51b2channel\u4e2d\u5143\u7d20\u6570\u91cf\u4e00\u6837\u3002\u539f\u56e0\u5c31\u5728\u4e8e\uff0c\u5df2\u7ecf\u68c0\u67e5\u8fc7\u7684channel\u7684\u72b6\u6001\u6709\u53ef\u80fd\u5728\u8c03\u7528\u4e86\u7c7b\u4f3c\u7684\u65b9\u6cd5\u8fd4\u56de\u4e4b\u540e\u5c31\u4fee\u6539\u4e86\uff0c\u56e0\u6b64\u8fd4\u56de\u6765\u7684\u503c\u5df2\u7ecf\u4e0d\u80fd\u591f\u53cd\u6620\u521a\u624d\u68c0\u67e5\u7684channel\u7684\u5f53\u524d\u72b6\u6001\u4e86\u3002<br \/>\n\u5c3d\u7ba1\u5728\u8c03\u7528closed(ch)\u8fd4\u56detrue\u7684\u60c5\u51b5\u4e0b\u505c\u6b62\u5411channel\u53d1\u9001\u503c\u662f\u53ef\u4ee5\u7684\uff0c\u4f46\u662f\u5982\u679c\u8c03\u7528closed(ch)\u8fd4\u56defalse\uff0c\u90a3\u4e48\u5173\u95edchannel\u6216\u8005\u7ee7\u7eed\u5411channel\u53d1\u9001\u503c\u5c31\u4e0d\u5b89\u5168\u4e86\uff08\u4f1apanic\uff09\u3002<\/p>\n<ul>\n<li>\n<h1><strong>The Channel Closing Principle<\/strong><\/h1>\n<\/li>\n<\/ul>\n<p>\u5728\u4f7f\u7528Go channel\u7684\u65f6\u5019\uff0c\u4e00\u4e2a\u9002\u7528\u7684\u539f\u5219\u662f\u4e0d\u8981\u4ece\u63a5\u6536\u7aef\u5173\u95edchannel\uff0c\u4e5f\u4e0d\u8981\u5728\u591a\u4e2a\u5e76\u53d1\u53d1\u9001\u7aef\u4e2d\u5173\u95edchannel\u3002\u6362\u53e5\u8bdd\u8bf4\uff0c\u5982\u679csender(\u53d1\u9001\u8005)\u53ea\u662f\u552f\u4e00\u7684sender\u6216\u8005\u662fchannel\u6700\u540e\u4e00\u4e2a\u6d3b\u8dc3\u7684sender\uff0c\u90a3\u4e48\u4f60\u5e94\u8be5\u5728sender\u7684goroutine\u5173\u95edchannel\uff0c\u4ece\u800c\u901a\u77e5receiver(s)(\u63a5\u6536\u8005\u4eec)\u5df2\u7ecf\u6ca1\u6709\u503c\u53ef\u4ee5\u8bfb\u4e86\u3002\u7ef4\u6301\u8fd9\u6761\u539f\u5219\u5c06\u4fdd\u8bc1\u6c38\u8fdc\u4e0d\u4f1a\u53d1\u751f\u5411\u4e00\u4e2a\u5df2\u7ecf\u5173\u95ed\u7684channel\u53d1\u9001\u503c\u6216\u8005\u5173\u95ed\u4e00\u4e2a\u5df2\u7ecf\u5173\u95ed\u7684channel\u3002\u4e0b\u9762\uff0c\u6211\u4eec\u5c06\u4f1a\u79f0\u4e0a\u9762\u7684\u539f\u5219\u4e3achannel closing principle<\/p>\n<ul>\n<li>\n<h1><strong>\u6253\u7834channel closing principle\u7684\u89e3\u51b3\u65b9\u6848<\/strong><\/h1>\n<\/li>\n<\/ul>\n<p>\u5982\u679c\u4f60\u56e0\u4e3a\u67d0\u79cd\u539f\u56e0\u4ece\u63a5\u6536\u7aef\uff08receiver side\uff09\u5173\u95edchannel\u6216\u8005\u5728\u591a\u4e2a\u53d1\u9001\u8005\u4e2d\u7684\u4e00\u4e2a\u5173\u95edchannel\uff0c\u90a3\u4e48\u4f60\u5e94\u8be5\u4f7f\u7528\u5217\u5728Golang panic\/recover Use Cases\u7684\u51fd\u6570\u6765\u5b89\u5168\u5730\u53d1\u9001\u503c\u5230channel\u4e2d\uff08\u5047\u8bbechannel\u7684\u5143\u7d20\u7c7b\u578b\u662fT\uff09<\/p>\n<pre>func SafeSend(ch chan T, value T) (closed bool) {\r\n\u00a0\u00a0\u00a0 defer func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if recover() != nil {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the return result can be altered \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ in a defer function call\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 closed = true\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }()\r\n\r\n\u00a0\u00a0\u00a0 ch &lt;- value \/\/ panic if ch is closed\r\n\u00a0\u00a0\u00a0 return false \/\/ &lt;=&gt; closed = false; return\r\n}\r\n<strong># defer \u53ea\u5728\u51fd\u6570return\u4e4b\u524d\u6267\u884c\u7684\u3002<\/strong><\/pre>\n<p>\u5982\u679cchannel ch\u6ca1\u6709\u88ab\u5173\u95ed\u7684\u8bdd\uff0c\u90a3\u4e48\u8fd9\u4e2a\u51fd\u6570\u7684\u6027\u80fd\u5c06\u548cch &lt;- value\u63a5\u8fd1\u3002\u5bf9\u4e8echannel\u5173\u95ed\u7684\u65f6\u5019\uff0cSafeSend\u51fd\u6570\u53ea\u4f1a\u5728\u6bcf\u4e2asender goroutine\u4e2d\u8c03\u7528\u4e00\u6b21\uff0c\u56e0\u6b64\u7a0b\u5e8f\u4e0d\u4f1a\u6709\u592a\u5927\u7684\u6027\u80fd\u635f\u5931\u3002<\/p>\n<p>\u540c\u6837\u7684\u60f3\u6cd5\u4e5f\u53ef\u4ee5\u7528\u5728\u4ece\u591a\u4e2agoroutine\u5173\u95edchannel\u4e2d\uff1a<\/p>\n<pre>func SafeClose(ch chan T) (justClosed bool) {\r\n\u00a0\u00a0\u00a0 defer func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if recover() != nil {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 justClosed = false\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }()\r\n\r\n\u00a0\u00a0\u00a0 \/\/ assume ch != nil here.\r\n\u00a0\u00a0\u00a0 close(ch) \/\/ panic if ch is closed\r\n\u00a0\u00a0\u00a0 return true\r\n}<\/pre>\n<p>\u5f88\u591a\u4eba\u559c\u6b22\u7528sync.Once\u6765\u5173\u95edchannel\uff1a<\/p>\n<pre>type MyChannel struct {\r\n\u00a0\u00a0\u00a0 C\u00a0\u00a0\u00a0 chan T\r\n\u00a0\u00a0\u00a0 once sync.Once\r\n}\r\n\r\nfunc NewMyChannel() *MyChannel {\r\n\u00a0\u00a0\u00a0 return &amp;MyChannel{C: make(chan T)}\r\n}\r\n\r\nfunc (mc *MyChannel) SafeClose() {\r\n\u00a0\u00a0\u00a0 mc.once.Do(func(){\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 close(mc.C)\r\n\u00a0\u00a0\u00a0 })\r\n}<\/pre>\n<p>\u5f53\u7136\u4e86\uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u7528sync.Mutex\u6765\u907f\u514d\u591a\u6b21\u5173\u95edchannel\uff1a<\/p>\n<pre>type MyChannel struct {\r\n\u00a0\u00a0\u00a0 C\u00a0\u00a0\u00a0\u00a0\u00a0 chan T\r\n\u00a0\u00a0\u00a0 closed bool\r\n\u00a0\u00a0\u00a0 mutex\u00a0 sync.Mutex\r\n}\r\n\r\nfunc NewMyChannel() *MyChannel {\r\n\u00a0\u00a0\u00a0 return &amp;MyChannel{C: make(chan T)}\r\n}\r\n\r\nfunc (mc *MyChannel) SafeClose() {\r\n\u00a0\u00a0\u00a0 mc.mutex.Lock()\r\n\u00a0\u00a0\u00a0 if !mc.closed {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 close(mc.C)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 mc.closed = true\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 mc.mutex.Unlock()\r\n}\r\n\r\nfunc (mc *MyChannel) IsClosed() bool {\r\n\u00a0\u00a0\u00a0 mc.mutex.Lock()\r\n\u00a0\u00a0\u00a0 defer mc.mutex.Unlock()\r\n\u00a0\u00a0\u00a0 return mc.closed\r\n}<\/pre>\n<p>\u6211\u4eec\u5e94\u8be5\u8981\u7406\u89e3\u4e3a\u4ec0\u4e48Go\u4e0d\u652f\u6301\u5185\u7f6eSafeSend\u548cSafeClose\u51fd\u6570\uff0c\u539f\u56e0\u5c31\u5728\u4e8e\u5e76\u4e0d\u63a8\u8350\u4ece\u63a5\u6536\u7aef\u6216\u8005\u591a\u4e2a\u5e76\u53d1\u53d1\u9001\u7aef\u5173\u95edchannel\u3002Golang\u751a\u81f3\u7981\u6b62\u5173\u95ed\u53ea\u63a5\u6536\uff08receive-only\uff09\u7684channel\u3002<\/p>\n<ul>\n<li>\n<h1><strong>\u4fdd\u6301channel closing principle\u7684\u4f18\u96c5\u65b9\u6848<\/strong><\/h1>\n<\/li>\n<\/ul>\n<p>\u4e0a\u9762\u7684SafeSend\u51fd\u6570\u6709\u4e00\u4e2a\u7f3a\u70b9\u662f\uff0c\u5728select\u8bed\u53e5\u7684case\u5173\u952e\u5b57\u540e\u4e0d\u80fd\u4f5c\u4e3a\u53d1\u9001\u64cd\u4f5c\u88ab\u8c03\u7528\uff08\u8bd1\u8005\u6ce8\uff1a\u7c7b\u4f3c\u4e8e case SafeSend(ch, t):\uff09\u3002\u53e6\u5916\u4e00\u4e2a\u7f3a\u70b9\u662f\uff0c\u5f88\u591a\u4eba\uff0c\u5305\u62ec\u6211\u81ea\u5df1\u90fd\u89c9\u5f97\u4e0a\u9762\u901a\u8fc7\u4f7f\u7528panic\/recover\u548csync\u5305\u7684\u65b9\u6848\u4e0d\u591f\u4f18\u96c5\u3002\u9488\u5bf9\u5404\u79cd\u573a\u666f\uff0c\u4e0b\u9762\u4ecb\u7ecd\u4e0d\u7528\u4f7f\u7528panic\/recover\u548csync\u5305\uff0c\u7eaf\u7cb9\u662f\u5229\u7528channel\u7684\u89e3\u51b3\u65b9\u6848\u3002\u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u603b\uff0csync.WaitGroup\u53ea\u662f\u7528\u6765\u8ba9\u4f8b\u5b50\u5b8c\u6574\u7684\u3002\u5b83\u7684\u4f7f\u7528\u5728\u5b9e\u8df5\u4e2d\u4e0d\u4e00\u5b9a\u4e00\u76f4\u90fd\u6709\u7528.<\/p>\n<p>M\u4e2areceivers\uff0c\u4e00\u4e2asender\uff0csender\u901a\u8fc7\u5173\u95eddata channel\u8bf4\u201c\u4e0d\u518d\u53d1\u9001\u201d<br \/>\n\u8fd9\u662f\u6700\u7b80\u5355\u7684\u573a\u666f\u4e86\uff0c\u5c31\u53ea\u662f\u5f53sender\u4e0d\u60f3\u518d\u53d1\u9001\u7684\u65f6\u5019\u8ba9sender\u5173\u95eddata \u6765\u5173\u95edchannel\uff1a<\/p>\n<pre>package main\r\n\r\nimport (\r\n\u00a0\u00a0\u00a0 \"time\"\r\n\u00a0\u00a0\u00a0 \"math\/rand\"\r\n\u00a0\u00a0\u00a0 \"sync\"\r\n\u00a0\u00a0\u00a0 \"log\"\r\n)\r\n\r\nfunc main() {\r\n\u00a0\u00a0\u00a0 rand.Seed(time.Now().UnixNano())\r\n\u00a0\u00a0\u00a0 log.SetFlags(0)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 const MaxRandomNumber = 100000\r\n\u00a0\u00a0\u00a0 const NumReceivers = 100\r\n\r\n\u00a0\u00a0\u00a0 wgReceivers := sync.WaitGroup{}\r\n\u00a0\u00a0\u00a0 wgReceivers.Add(NumReceivers)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 dataCh := make(chan int, 100)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ the sender\r\n\u00a0\u00a0\u00a0 go func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if value := rand.Intn(MaxRandomNumber); value == 0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the only sender can close the channel safely.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 close(dataCh)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } else {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dataCh &lt;- value\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }()\r\n\r\n\u00a0\u00a0\u00a0 \/\/ receivers\r\n\u00a0\u00a0\u00a0 for i := 0; i &lt; NumReceivers; i++ {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 go func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 defer wgReceivers.Done()\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ receive values until dataCh is closed and\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the value buffer queue of dataCh is empty.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for value := range dataCh {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 log.Println(value)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }()\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 wgReceivers.Wait()\r\n}<\/pre>\n<p>\u4e00\u4e2areceiver\uff0cN\u4e2asender\uff0creceiver\u901a\u8fc7\u5173\u95ed\u4e00\u4e2a\u989d\u5916\u7684signal channel\u8bf4\u201c\u8bf7\u505c\u6b62\u53d1\u9001\u201d<br \/>\n\u8fd9\u79cd\u573a\u666f\u6bd4\u4e0a\u4e00\u4e2a\u8981\u590d\u6742\u4e00\u70b9\u3002\u6211\u4eec\u4e0d\u80fd\u8ba9receiver\u5173\u95eddata channel\uff0c\u56e0\u4e3a\u8fd9\u4e48\u505a\u5c06\u4f1a\u6253\u7834channel closing principle\u3002\u4f46\u662f\u6211\u4eec\u53ef\u4ee5\u8ba9receiver\u5173\u95ed\u4e00\u4e2a\u989d\u5916\u7684signal channel\u6765\u901a\u77e5sender\u505c\u6b62\u53d1\u9001\u503c\uff1a<\/p>\n<pre>package main\r\n\r\nimport (\r\n\u00a0\u00a0\u00a0 \"time\"\r\n\u00a0\u00a0\u00a0 \"math\/rand\"\r\n\u00a0\u00a0\u00a0 \"sync\"\r\n\u00a0\u00a0\u00a0 \"log\"\r\n)\r\n\r\nfunc main() {\r\n\u00a0\u00a0\u00a0 rand.Seed(time.Now().UnixNano())\r\n\u00a0\u00a0\u00a0 log.SetFlags(0)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 const MaxRandomNumber = 100000\r\n\u00a0\u00a0\u00a0 const NumSenders = 1000\r\n\r\n\u00a0\u00a0\u00a0 wgReceivers := sync.WaitGroup{}\r\n\u00a0\u00a0\u00a0 wgReceivers.Add(1)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 dataCh := make(chan int, 100)\r\n\u00a0\u00a0\u00a0 stopCh := make(chan struct{})\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ stopCh is an additional signal channel.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Its sender is the receiver of channel dataCh.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Its reveivers are the senders of channel dataCh.\r\n\r\n\u00a0\u00a0\u00a0 \/\/ senders\r\n\u00a0\u00a0\u00a0 for i := 0; i &lt; NumSenders; i++ {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 go func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 value := rand.Intn(MaxRandomNumber)\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &lt;- stopCh:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case dataCh &lt;- value:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }()\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \/\/ the receiver\r\n\u00a0\u00a0\u00a0 go func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 defer wgReceivers.Done()\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for value := range dataCh {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if value == MaxRandomNumber-1 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the receiver of the dataCh channel is\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ also the sender of the stopCh cahnnel.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ It is safe to close the stop channel here.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 close(stopCh)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 log.Println(value)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }()\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 wgReceivers.Wait()\r\n}<\/pre>\n<p>\u6b63\u5982\u6ce8\u91ca\u8bf4\u7684\uff0c\u5bf9\u4e8e\u989d\u5916\u7684signal channel\u6765\u8bf4\uff0c\u5b83\u7684sender\u662fdata channel\u7684receiver\u3002\u8fd9\u4e2a\u989d\u5916\u7684signal channel\u88ab\u5b83\u552f\u4e00\u7684sender\u5173\u95ed\uff0c\u9075\u5b88\u4e86channel closing principle\u3002<\/p>\n<p>M\u4e2areceiver\uff0cN\u4e2asender\uff0c\u5b83\u4eec\u5f53\u4e2d\u4efb\u610f\u4e00\u4e2a\u901a\u8fc7\u901a\u77e5\u4e00\u4e2amoderator\uff08\u4ef2\u88c1\u8005\uff09\u5173\u95ed\u989d\u5916\u7684signal channel\u6765\u8bf4\u201c\u8ba9\u6211\u4eec\u7ed3\u675f\u6e38\u620f\u5427\u201d<br \/>\n\u8fd9\u662f\u6700\u590d\u6742\u7684\u573a\u666f\u4e86\u3002\u6211\u4eec\u4e0d\u80fd\u8ba9\u4efb\u610f\u7684receivers\u548csenders\u5173\u95eddata channel\uff0c\u4e5f\u4e0d\u80fd\u8ba9\u4efb\u4f55\u4e00\u4e2areceivers\u901a\u8fc7\u5173\u95ed\u4e00\u4e2a\u989d\u5916\u7684signal channel\u6765\u901a\u77e5\u6240\u6709\u7684senders\u548creceivers\u9000\u51fa\u6e38\u620f\u3002\u8fd9\u4e48\u505a\u7684\u8bdd\u4f1a\u6253\u7834channel closing principle\u3002\u4f46\u662f\uff0c\u6211\u4eec\u53ef\u4ee5\u5f15\u5165\u4e00\u4e2amoderator\u6765\u5173\u95ed\u4e00\u4e2a\u989d\u5916\u7684signal channel\u3002\u8fd9\u4e2a\u4f8b\u5b50\u7684\u4e00\u4e2a\u6280\u5de7\u662f\u600e\u4e48\u901a\u77e5moderator\u53bb\u5173\u95ed\u989d\u5916\u7684signal channel\uff1a<\/p>\n<pre>package main\r\n\r\nimport (\r\n\u00a0\u00a0\u00a0 \"time\"\r\n\u00a0\u00a0\u00a0 \"math\/rand\"\r\n\u00a0\u00a0\u00a0 \"sync\"\r\n\u00a0\u00a0\u00a0 \"log\"\r\n\u00a0\u00a0\u00a0 \"strconv\"\r\n)\r\n\r\nfunc main() {\r\n\u00a0\u00a0\u00a0 rand.Seed(time.Now().UnixNano())\r\n\u00a0\u00a0\u00a0 log.SetFlags(0)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 const MaxRandomNumber = 100000\r\n\u00a0\u00a0\u00a0 const NumReceivers = 10\r\n\u00a0\u00a0\u00a0 const NumSenders = 1000\r\n\r\n\u00a0\u00a0\u00a0 wgReceivers := sync.WaitGroup{}\r\n\u00a0\u00a0\u00a0 wgReceivers.Add(NumReceivers)\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 dataCh := make(chan int, 100)\r\n\u00a0\u00a0\u00a0 stopCh := make(chan struct{})\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ stopCh is an additional signal channel.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Its sender is the moderator goroutine shown below.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Its reveivers are all senders and receivers of dataCh.\r\n\u00a0\u00a0\u00a0 toStop := make(chan string, 1)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the channel toStop is used to notify the moderator\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ to close the additional signal channel (stopCh).\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Its senders are any senders and receivers of dataCh.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Its reveiver is the moderator goroutine shown below.\r\n\r\n\u00a0\u00a0\u00a0 var stoppedBy string\r\n\r\n\u00a0\u00a0\u00a0 \/\/ moderator\r\n\u00a0\u00a0\u00a0 go func() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 stoppedBy = &lt;- toStop \/\/ part of the trick used to notify the moderator\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ to close the additional signal channel.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 close(stopCh)\r\n\u00a0\u00a0\u00a0 }()\r\n\r\n\u00a0\u00a0\u00a0 \/\/ senders\r\n\u00a0\u00a0\u00a0 for i := 0; i &lt; NumSenders; i++ {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 go func(id string) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 value := rand.Intn(MaxRandomNumber)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if value == 0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ here, a trick is used to notify the moderator\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ to close the additional signal channel.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case toStop &lt;- \"sender#\" + id:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 default:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the first select here is to try to exit the\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ goroutine as early as possible.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &lt;- stopCh:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 default:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &lt;- stopCh:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case dataCh &lt;- value:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }(strconv.Itoa(i))\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \/\/ receivers\r\n\u00a0\u00a0\u00a0 for i := 0; i &lt; NumReceivers; i++ {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 go func(id string) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 defer wgReceivers.Done()\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ same as senders, the first select here is to \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ try to exit the goroutine as early as possible.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &lt;- stopCh:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 default:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &lt;- stopCh:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case value := &lt;-dataCh:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if value == MaxRandomNumber-1 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ the same trick is used to notify the moderator \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ to close the additional signal channel.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 select {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case toStop &lt;- \"receiver#\" + id:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 default:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 log.Println(value)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }(strconv.Itoa(i))\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ...\r\n\u00a0\u00a0\u00a0 wgReceivers.Wait()\r\n\u00a0\u00a0\u00a0 log.Println(\"stopped by\", stoppedBy)\r\n}<\/pre>\n<p>\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4ecd\u7136\u9075\u5b88\u7740channel closing principle\u3002<br \/>\n\u8bf7\u6ce8\u610fchannel toStop\u7684\u7f13\u51b2\u5927\u5c0f\u662f1.\u8fd9\u662f\u4e3a\u4e86\u907f\u514d\u5f53mederator goroutine \u51c6\u5907\u597d\u4e4b\u524d\u7b2c\u4e00\u4e2a\u901a\u77e5\u5c31\u5df2\u7ecf\u53d1\u9001\u4e86\uff0c\u5bfc\u81f4\u4e22\u5931\u3002<\/p>\n<ul>\n<li>\n<h1><strong>\u66f4\u591a\u7684\u573a\u666f\uff1f<\/strong><\/h1>\n<\/li>\n<\/ul>\n<p>\u5f88\u591a\u7684\u573a\u666f\u53d8\u4f53\u662f\u57fa\u4e8e\u4e0a\u9762\u4e09\u79cd\u7684\u3002\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u4e00\u4e2a\u57fa\u4e8e\u6700\u590d\u6742\u60c5\u51b5\u7684\u53d8\u4f53\u53ef\u80fd\u8981\u6c42receivers\u8bfb\u53d6buffer channel\u4e2d\u5269\u4e0b\u6240\u6709\u7684\u503c\u3002\u8fd9\u5e94\u8be5\u5f88\u5bb9\u6613\u5904\u7406\uff0c\u6240\u6709\u8fd9\u7bc7\u6587\u7ae0\u4e5f\u5c31\u4e0d\u63d0\u4e86\u3002<br \/>\n\u5c3d\u7ba1\u4e0a\u9762\u4e09\u79cd\u573a\u666f\u4e0d\u80fd\u8986\u76d6\u6240\u6709Go channel\u7684\u4f7f\u7528\u573a\u666f\uff0c\u4f46\u5b83\u4eec\u662f\u6700\u57fa\u7840\u7684\uff0c\u5b9e\u8df5\u4e2d\u7684\u5927\u591a\u6570\u573a\u666f\u90fd\u53ef\u4ee5\u5206\u7c7b\u5230\u90a3\u4e09\u79cd\u4e2d\u3002<\/p>\n<ul>\n<li>\n<h1><strong>\u7ed3\u8bba<\/strong><\/h1>\n<\/li>\n<\/ul>\n<p>\u8fd9\u91cc\u6ca1\u6709\u4e00\u79cd\u573a\u666f\u8981\u6c42\u4f60\u53bb\u6253\u7834channel closing principle\u3002\u5982\u679c\u4f60\u9047\u5230\u4e86\u8fd9\u79cd\u573a\u666f\uff0c\u8bf7\u601d\u8003\u4e00\u4e0b\u4f60\u7684\u8bbe\u8ba1\u5e76\u91cd\u5199\u4f60\u7684\u4ee3\u7801\u3002\u7528Go\u7f16\u7a0b\u5c31\u50cf\u5728\u521b\u4f5c\u827a\u672f\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u51e0\u5929\u524d\uff0c\u6211\u5199\u4e86\u4e00\u7bc7\u6587\u7ae0\u6765\u8bf4\u660egolang\u4e2dchannel\u7684\u4f7f\u7528\u89c4\u8303\u3002\u5728reddit\u548cHN\uff0c\u90a3\u7bc7\u6587\u7ae0\u6536\u5230\u4e86\u5f88\u591a\u8d5e\u540c\uff0c\u4f46\u662f\u6211\u4e5f\u6536\u5230\u4e86\u4e0b\u9762\u51e0\u4e2a\u5173\u4e8eGo channel\u8bbe\u8ba1\u548c\u89c4\u8303\u7684\u6279\u8bc4\uff1a \u5728\u4e0d\u80fd\u66f4\u6539channel\u72b6\u6001\u7684\u60c5\u51b5\u4e0b\uff0c\u6ca1\u6709\u7b80\u5355\u666e\u904d\u7684\u65b9\u5f0f\u6765\u68c0\u67e5channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u4e86 \u5173\u95ed\u5df2\u7ecf\u5173\u95ed\u7684channel\u4f1a\u5bfc\u81f4panic\uff0c\u6240\u4ee5\u5728closer(\u5173\u95ed\u8005)\u4e0d\u77e5\u9053channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u7684\u60c5\u51b5\u4e0b\u53bb\u5173\u95edchannel\u662f\u5f88\u5371\u9669\u7684 \u53d1\u9001\u503c\u5230\u5df2\u7ecf\u5173\u95ed\u7684channel\u4f1a\u5bfc\u81f4panic\uff0c\u6240\u4ee5\u5982\u679csender(\u53d1\u9001\u8005)\u5728\u4e0d\u77e5\u9053channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u7684\u60c5\u51b5\u4e0b\u53bb\u5411channel\u53d1\u9001\u503c\u662f\u5f88\u5371\u9669\u7684 &nbsp; \u90a3\u4e9b\u6279\u8bc4\u770b\u8d77\u6765\u90fd\u5f88\u6709\u9053\u7406\uff08\u5b9e\u9645\u4e0a\u5e76\u6ca1\u6709\uff09\u3002\u662f\u7684\uff0c\u6ca1\u6709\u4e00\u4e2a\u5185\u7f6e\u51fd\u6570\u53ef\u4ee5\u68c0\u67e5\u4e00\u4e2achannel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\u3002\u5982\u679c\u4f60\u80fd\u786e\u5b9a\u4e0d\u4f1a\u5411channel\u53d1\u9001\u4efb\u4f55\u503c\uff0c\u90a3\u4e48\u4e5f\u786e\u5b9e\u9700\u8981\u4e00\u4e2a\u7b80\u5355\u7684\u65b9\u6cd5\u6765\u68c0\u67e5channel\u662f\u5426\u5df2\u7ecf\u5173\u95ed\uff1a package main import &#8220;fmt&#8221; type T int func IsClosed(ch &lt;-chan T) bool { \u00a0\u00a0\u00a0 select { \u00a0\u00a0\u00a0 case &lt;-ch: \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return true \u00a0\u00a0\u00a0 default: \u00a0\u00a0\u00a0 } \u00a0\u00a0\u00a0 return false } func main() { \u00a0\u00a0\u00a0 c := make(chan T) \u00a0\u00a0\u00a0 fmt.Println(IsClosed(c)) \/\/ false \u00a0\u00a0\u00a0 close(c) \u00a0\u00a0\u00a0 fmt.Println(IsClosed(c)) \/\/ true [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[],"class_list":["post-15446","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/posts\/15446","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/comments?post=15446"}],"version-history":[{"count":1,"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/posts\/15446\/revisions"}],"predecessor-version":[{"id":15447,"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/posts\/15446\/revisions\/15447"}],"wp:attachment":[{"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/media?parent=15446"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/categories?post=15446"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fwq.ai\/blog\/wp-json\/wp\/v2\/tags?post=15446"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}