在go例程中使用两个fmt.printlns时出现死锁?

xoefb8l8  于 2022-12-07  发布在  Go
关注(0)|答案(2)|浏览(119)

我正在学习围棋,我在操场上做实验。我有一个非常简单的围棋代码。我试图在围棋例程中同时使用结构和切片。我不确定这是否会是我在生产中使用的东西,但它似乎有点偏离,所以在这里:

func main() {
    routinemsg := make(chan []Person)
    routinemsg2 := make(chan []Person)

    // create the person records
    p1 := newPerson("john doe", 25)
    p2 := newPerson("dohn joe", 52)
    p3 := newPerson("bohn joo", 30)

    // send a slice of Person to the first routine
    go func() { routinemsg <- []Person{p1, p2} }()

    // retrieve the slice from the first routine[in the append]
    // append p3 to the slice retrieved from the first routine
    // send the new slice to the second routine
    go func() { routinemsg2 <- append(<-routinemsg, p3) }()
    
    // I am able to see the first Println but when I insert the second one I get a deadlock error
    // also, same error if I use one Println with 2 arguments.
    fmt.Println(<-routinemsg)
    fmt.Println(<-routinemsg2)
}

我听说过等待小组,但还不知道他们!所以,对我好点:D和谢谢你的时间

laximzn5

laximzn51#

routinemsg上只有一个发送操作,但您有2个接收操作:一个在已启动的goroutine中,另一个在main goroutine中,一个发送的值只能被一个接收者接收一次。
如果启动的goroutine首先从routinemsg接收到消息,那么它将是一个死锁:main中的接收将永远阻塞。
如果main goroutine首先接收,那么被启动的goroutine将永远阻塞(试图从main接收),因此它永远不能在routinemsg2上发送任何东西,因此main中从routinemsg2接收的东西也将永远阻塞:再次陷入僵局。
删除main()中的fmt.Println(<-routinemsg)行,然后从routinemsg2的最终接收可以(最终)继续,并将打印包含p1p2p3的切片:

[{john doe 25} {dohn joe 52} {bohn joo 30}]

Go Playground上试用。

yqkkidmi

yqkkidmi2#

作为对@icza回答的补充:如果您使用如下所示的 * 缓冲通道 *,

buffered := make(chan string, 2)
    buffered <- "1"
    buffered <- "2"

    fmt.Println(<-buffered)
    fmt.Println(<-buffered)

您可以从同一通道多次发送和接收值。

但是,您仍然通过传递给make的参数来限制发送和接收的次数!此外,对于缓冲通道,您将总是按照发送到通道的顺序接收值。

因此,从第二个接收器接收的第二个值将始终是发送到通道的第二个值。

相关问题