理解 Go 通道死锁

huangapple go评论102阅读模式
英文:

Understanding Go channel deadlocks

问题

以下是您提供的代码的翻译:

package main

import (
	"fmt"
	"time"
)

func main() {
	p := producer()
	for c := range p {
		fmt.Println(c)
	}
}

func producer() <-chan string {
	ch := make(chan string)
	go func() {
		for i := 0; i < 5; i++ {
			ch <- fmt.Sprint("hello", i)
			time.Sleep(1 * time.Second)
		}
		// 注释掉下面的代码以显示问题
		// close(ch)
	}()
	return ch
}

运行上述代码将打印出5条消息,然后出现"all go routines are a sleep - deadlock error"错误。我理解,如果我关闭通道,错误就会消失。

我想要理解的是,Go运行时如何知道代码将无限期地等待通道,并且没有其他内容将向通道发送数据。

现在,如果我在main()函数中添加一个额外的Go协程,它不会抛出任何错误,并且会继续等待通道。

go func() {
	for {
		time.Sleep(2 * time.Millisecond)
	}
}()

这是否意味着Go运行时只是查找可能向通道发送数据的正在运行的Go协程的存在,因此不会抛出死锁错误?

英文:
package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	p := producer()
	for c := range p {
		fmt.Println(c)
	}
}

func producer() &lt;-chan string {
	ch := make(chan string)
	go func() {
		for i := 0; i &lt; 5; i++ {
			ch &lt;- fmt.Sprint(&quot;hello&quot;, i)
			time.Sleep(1 * time.Second)
		}
        // commented the below to show the issue
        // close(ch)
	}()
	return ch
}

Running the above code will print 5 messages and then give a "all go routines are a sleep - deadlock error". I understand that if I close the channel the error is gone.

The thing I would like to understand is how does go runtime know that the code will be waiting infinitely on the channel and that there is nothing else that will be sending data into the channel.

Now if I add an additional go routine to the main() function.. it does not throw any error and keeps waiting on the channel.

go func() {
		for {
			time.Sleep(2 * time.Millisecond)
		}
	}()

So does this mean.. the go runtime is just looking for presence of a running go routine that could potentially send data into the channel and hence not throwing the deadlock error ?

答案1

得分: 7

如果你想更深入了解Go如何实现死锁检测,可以查看代码中抛出“all goroutines are asleep - deadlock!”的位置:https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751

看起来,Go运行时在如何计算有多少个goroutine、有多少个空闲以及有多少个正在等待锁的goroutine(不确定在通道I/O上等待的goroutine是否会增加)方面保持了一些相当简单的记账。在任何给定的时间(与运行时的其余部分串行化),它只是进行一些算术计算,并检查是否“all - idle - locked > 0”...如果是这样,那么程序仍然可以继续进行...如果是0,那么你肯定发生了死锁。

通过通过阻止goroutine通过无限循环进入睡眠状态(就像你在实验中所做的那样,并且显然运行时对计时器的睡眠处理方式不同),你可能会引入活锁。在这种情况下,运行时将无法检测到死锁,并且会一直运行下去。

此外,我不确定运行时何时检查死锁-如果你感兴趣,进一步检查调用checkdead()的代码可能会提供一些见解。

免责声明-我不是Go核心开发人员,我只是在电视上扮演一个。

英文:

If you want some more insight into how Go implements the deadlock detection, have a look at the place in the code that throws the &quot;all goroutines are asleep - deadlock!&quot;: https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751

It looks like the Go runtime keeps some fairly simple accounting on how many goroutines there are, how many are idle, and how many are sleeping for locks (not sure which one sleep on channel I/O will increment). At any given time (serialized with the rest of the runtime), it just does some arithmetic and checks if all - idle - locked &gt; 0... if so, then the program could still make progress... if it's 0, then you're definitely deadlocked.

It's possible you could introduce a livelock by preventing a goroutine from sleeping via an infinite loop (like what you did in your experiment, and apparently sleep for timers isn't treated the same by the runtime). The runtime wouldn't be able to detect a deadlock in that case, and run forever.

Furthermore, I'm not sure when exactly the runtime checks for deadlocks- further inspection of who calls that checkdead() may yield some insight there, if you're interested.

DISCLAIMER- I'm not a Go core developer, I just play one on TV 理解 Go 通道死锁

答案2

得分: 5

运行时在所有goroutine都被阻塞在通道和互斥操作上时,会出现“所有goroutine都处于休眠状态-死锁错误”的恐慌错误。

休眠的goroutine没有在这些操作之一上被阻塞。因此,没有死锁,也没有恐慌。

英文:

The runtime panics with the "all go routines are a sleep - deadlock error" error when all goroutines are blocked on channel and mutex operations.

The sleeping goroutine does not block on one of these operations. There is no deadlock and therefore no panic.

huangapple
  • 本文由 发表于 2017年8月25日 05:31:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/45871203.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定