写入永远被阻塞的频道

Write to channel blocked forever

我陷入了一种奇怪的情况,即对通道的写入操作从未发生过。

package main

import (
    "fmt"
    "time"
)

func main() {
    c := make(chan int)
    s := make(chan bool)
    k := make(chan bool)
    fmt.Println("start")
    go func() {
    fmt.Println("routine 1")
        s <- true
    }()
    go func() {
    fmt.Println("routine 2")
        for {
            select {
            case  <-s :
                for i := 0; i < 3; i++ {
                    fmt.Println("before")
                    c <- i
                    fmt.Println("after")
                }       
            case <- k :
                fmt.Println("k ready")
                break
            }
        }
    }()

    go func() {
        fmt.Println("routine 3")
        for {
            select {
                case x := <- c :
                fmt.Println("x=", x)
                k <- true
                fmt.Println("k done")

            }
        }
    }()

    time.Sleep(1000 * time.Millisecond)
}

这是输出:

start
routine 1
routine 2
before
routine 3
x= 0
after
before

我想知道为什么写入通道 k 会阻塞,但日志语句 fmt.Println("k ready") 从未打印出来。

这是我的想法:

根据我的说法,它应该能够写入通道 k 然后 goroutine 的情况 2 应该执行并打印 "k ready"

任何人都可以解释为什么写入被阻止的频道吗? 作为修复,我知道我可以增加通道 c 的缓冲区大小,所有内容都会被打印出来,但我对修复此问题不感兴趣,相反我想了解这种情况。

理解上述案例很好blog

你遇到了死锁。

  • goroutine 1 写入 s 然后退出
  • goroutine 2 从 s 读取,并写入 c
  • goroutine 3 从 c 读取,并写入 k,这会阻塞,因为没有从 k 读取任何内容,因为 goroutine 2 在写入 [=15] 时被阻塞=] 以上。
  • goroutine 2 再次写入 c 哪个块因为 goroutine 3 仍在尝试写入 k 因此没有从 c
  • 读取

与您所说的相反,您的缓冲区大小不是 1。您的缓冲区大小为零(即无缓冲通道),因此写入将阻塞,直到有内容读取。这可能是你误解的根源。根据 language specification:

A new, initialized channel value can be made using the built-in function make, which takes the channel type and an optional capacity as arguments:

make(chan int, 100)

The capacity, in number of elements, sets the size of the buffer in the channel. If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives). A nil channel is never ready for communication.