2017-08-24 121 views
1
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) 
     } 
     // commented the below to show the issue 
     // close(ch) 
    }() 
    return ch 
} 

运行上面的代码将打印5条消息,然后给出一个“所有去例程是睡眠 - 死锁错误”。我明白,如果我关闭了频道,错误消失了。了解走通道死锁

我想了解的是,运行时如何知道代码将无限期地等待在通道上,并且没有其他任何事情将数据发送到通道中。

现在,如果我为main()函数添加额外的例程,它不会抛出任何错误并持续等待通道。

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

那么,这是否意味着.. Go运行时只是寻找一个运行去例程可能将数据发送到通道中,因此不扔僵局错误的存在?

回答

3

当所有goroutines在通道和互斥操作上被阻塞时,运行时恐慌与“所有去例程是睡眠 - 死锁错误”错误。

睡觉的goroutine不会阻止这些操作之一。没有僵局,因此没有恐慌。

4

如果你想要一些更深入地转到如何实现死锁检测,看看在代码的地方抛出的"all goroutines are asleep - deadlock!"https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751

它看起来像围棋运行时将如何一些相当简单的会计有很多goroutines,有多少人闲着,有多少人正在睡觉(不知道通道I/O上哪一个人会睡觉)。在任何给定时间(与运行时的其余部分一起序列化),它只是执行一些算术运算并检查是否all - idle - locked > 0 ...如果是,那么程序仍然可以取得进展...如果它是0,那么你肯定是死锁了。

可能你可以通过阻止goroutine通过无限循环睡眠来引入一个活锁(就像你在实验中所做的一样,显然睡眠的定时器在运行时并不一样)。在这种情况下,运行时将无法检测到死锁,并永远运行。此外,我不确定运行时间是否检查死锁 - 如果您有兴趣,可以进一步检查谁调用checkdead()可能会产生一些洞察。

卸弃我不是一个围棋核心开发者,我只是玩一个在电视上:-)

+0

感谢@Eddy R代表的信息。尝试给+1,但由于我的低点,系统不允许。 – tblogger