<p>I have the feeling I keep running into deadlocks most of the time I try to use channels in Go. I have the feeling I can't keep the mental model on how to correctly signal the closing of the channel. Do you guys have any advise or tips to get it right ?</p>
<hr/>**评论:**<br/><br/>riking27: <pre><p>The language basically requires that you have a single piece of code responsible for closing a given channel. Anything else is prone to panics.</p>
<p>If you're having trouble figuring out:</p>
<ul>
<li>when multiple producers are all exhausted: use a sync.WaitGroup</li>
<li>how to abandon pending items in the channel (when client goes away): use a <code>done chan struct{}</code>, such as provided by <code>context</code></li>
</ul></pre>stormandsong: <pre><p><code>sync.Once</code> is also extraordinarily useful here.</p></pre>earthboundkid: <pre><p>The reason that double closing a channel causes a panic is that a design where multiple goroutines can close a channel is subject to a race condition. The language is trying to force you to use a better design for your concurrency. Once you’ve done it correctly once or twice, it gets easier to reason about. </p></pre>sybrandy: <pre><p>I believe the recommendation by Dave Cheney is that the sender is who closes the channel. This simplifies things greatly because since it's what will be sending on the channel, it can make sure you don't try to send on a closed channel.</p></pre>nsd433: <pre><blockquote>
<p>deadlocks</p>
</blockquote>
<p>If communication flows two ways between two goroutines, via two channels, then you have one goroutine send and receive normally, and the second goroutine has to always be willing to yield while it is blocking wait to send to the first.</p>
<p>In other words, the 1st goroutine can do</p>
<pre><code>chan_r1_to_r2 <- msg
</code></pre>
<p>while the 2nd goroutine must do</p>
<pre><code>sent:
for {
select {
case chan_to_r1 <- msg:
break sent
case msg2 := <- chan_r1_to_r2:
// process or pend msg2 and go back to trying to send msg (if still applicable)
}
}
</code></pre>
<p>This is the same sort of idea as sorting your mutexes so they are always locked in a certain order to avoid deadlocks.</p>
<p>Sometimes the design can be changed so that the job done by r2 can be split into an r2 which receives, and an r3 which sends. That results in cleaner code as long as the locking between r2 and r3 is minimal.</p>
<p>The wrong way is to have r2 do</p>
<pre><code>go func(msg) { chan_r2_to_r1 <- msg }
</code></pre>
<p>because once several of these are pending there's no controlling the order in which they send to the channel.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传