go - 为什么 channel 没有成为结构的成员

标签 go concurrency channel goroutine

代码:https://play.golang.org/p/Oh3oTa7GIPX

type a struct {
    c chan bool
}

func (a *a) do() {
    a.c <- true
}

type b struct {
    c chan bool
    a a
}

func main() {
    b := b{
        c: make(chan bool),
        a: a{c: make(chan bool)},
    }

    go b.s()
    b.c <- true

    // below is to stay main gorutine alive
    done := make(chan bool)
    go func() {
        time.Sleep(10 * time.Second)
        done <- true
    }()
    for {
        select {
        case <-done:
            fmt.Println("Done!")
            return
        }
    }
}

func (b *b) s() {
    for {
        select {
        case <-b.c:
            fmt.Println("b c")
            b.a.do()

        case <-b.a.c:
            fmt.Println("b a c")
        }
    }
}

上面的实际输出是

b c
Done!

预期输出:

b c
b a c
Done !

我不明白为什么它不打印 b a c

代码是不言自明的,如果还需要更多细节请询问

最佳答案

你的 main goroutine 在 b.c 上发送一个值,然后等待:

b.c <- true

您从 main 启动的 goroutine:

go b.s()

这是从 b.c 收到的, 也来自 b.a.c :

func (b *b) s() {
    for {
        select {
        case <-b.c:
            fmt.Println("b c")
            b.a.do()

        case <-b.a.c:
            fmt.Println("b a c")
        }
    }
}

如果从 b.c 收到一个值,这个 goroutine 尝试在 b.a.c 上发送(在 a.do() 方法中),并且您希望这个相同 goroutine 从 b.a.c 接收.但是因为 b.a.c是无缓冲的,发送将阻塞,因此它永远不会到达 b.s() 中的下一次迭代它可以/将从哪里接收b.a.c .

如果一个 channel 是无缓冲的,只有当有另一个 goroutine 准备好从它接收时,它的发送才会继续。

如果你使 b.a.c缓冲 channel ,发送可以在不阻塞的情况下继续进行,因此在下一次迭代中可以接收它:

a: a{c: make(chan bool, 1)}

通过此更改,您将获得预期的输出。在 Go Playground 上试用.

关于go - 为什么 channel 没有成为结构的成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57770328/

相关文章:

go - 如何返回 channel

go - 如何在没有前导零的情况下截断并完全重写文件?

go - 如何将正符号 int32 值转换为负值?

go - 在这两个迭代器中减少重复的好方法是什么?

go - 在没有接收方的情况下,是否可以保留数据打开的缓冲 channel ?

c# - 线程可以做什么基于任务的异步模式 (TAP) 和带有任务(或 Task<T>)的任务并行性 (TPL) 无法做到的事情?

c# - 仅当满足条件时才从 ConcurrentQueue 中出队

go - golang游览网络爬虫练习的简单解决方案

json - Marshal/Unmarshal int 类型

go - 是否有更简洁的方法来创建在 channel 上接收后取消的上下文?