【问题标题】:buffered/unbuffered go channels and deadlock缓冲/非缓冲 go 通道和死锁
【发布时间】:2017-09-06 10:50:11
【问题描述】:

为了学习,我使用这段代码来玩 goroutines。我无法得到不同的东西:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string) // <A>
    ch2 := make(chan string) // <B>

    go test(ch1, ch2)
    ch1 <- "hi" // <C>
    ch2 <- "bye" // <D>
    fmt.Scanln()
}

func test(ch1 chan string, ch2 chan string) {
    timeout := time.After(time.Second * 2) // <E>
    defer func() { fmt.Println("returning") }()
    for {
        select {
        case s := <-ch1:
            fmt.Println(s, "1")
            ch2 <- "ch2"
            fmt.Println("after 1")
        case s := <-ch2:
            fmt.Println(s, "2")
            ch1 <- "ch1"
            fmt.Println("after 2")
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
}

如果我按原样运行代码,我总是会得到:

嗨 1
致命错误:所有 goroutine 都处于休眠状态 - 死锁!

关键是程序完全等待E部分中指定的持续时间。我的意思是,如果我增加睡眠时间,则在该时间过去之后会出现致命错误。所以第一个问题是:

1- 究竟发生了什么?谁能解释这种行为?

1-1- 为什么代码总是打印"hi 1"?我已经阅读了从就绪频道中随机选择的 select 语句,那么为什么总是"hi 1"?如果我交换 CD 那么它总是打印"bye 2"

1-2- 为什么程序要等待一段时间然后死锁?

现在假设我在 AB 中缓冲大小为 1 的通道,即:

ch1 := make(chan string, 1) // <A>
ch2 := make(chan string, 1) // <B>

现在每次我运行程序时,它都会随机打印"hi 1""bye 2"(仅一次)并永远等待(如果我按主函数中的代码输入程序退出)

2- 现在会发生什么?请解释一下。

最后,如果我将缓冲区大小设为 2(或更大):​​

ch1 := make(chan string, 2) // <A>
ch2 := make(chan string, 2) // <B>

程序按预期运行并依次打印"hi 1""bye 2",直到E 部分中编码的时间过去:

ch1 1  
after 1  
ch2 2  
after 2  
ch1 1  
after 1  
ch1 1  
after 1  
ch2 2   
.  
.  
.  
timed out  
returning  

我认为这里一切都很清楚,因为通道以适当的大小缓冲,所以一切都按预期工作。

【问题讨论】:

  • 不确定您要在这里实现什么。这个程序应该提前退出,因为没有任何东西阻塞主函数。我认为这不是预期的行为。
  • 使用等待组调查golang.org/pkg/sync/#WaitGroup
  • 程序不会退出,因为在 main 函数的末尾调用了 fmt.Scanln。

标签: go goroutine


【解决方案1】:
  1. 想想当所有通道发送的东西都完成后会发生什么:你选择在一个无限的for循环中运行,一旦定时器触发,什么都不能运行。

1.1。你先在ch1上发送。选择循环从 可以 运行的所有路径中随机选择。第二种情况无法运行,因为 ch2 中没有任何内容,直到您通过 ch1 获得“hi”。

1.2。你的超时时间。

  1. 您的频道已缓冲,即使没有人直接读取它们,您也可以将其发送到其中。所以 ch1&lt;-"hi" 和 `ch2

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 2021-08-15
    • 2018-04-15
    • 2019-01-07
    • 2012-10-17
    • 2021-10-13
    相关资源
    最近更新 更多