Go为什么要写封闭频道?

Eve*_*ton 12 concurrency channel go panic goroutine

Go为什么要写封闭频道?

虽然可以使用这个value, ok := <-channel成语从频道中读取,因此可以测试ok结果是否可以打开一个封闭的频道:

// reading from closed channel

package main

import "fmt"

func main() {
    ch := make(chan int, 1)
    ch <- 2
    close(ch)

    read(ch)
    read(ch)
    read(ch)
}

func read(ch <-chan int) {
    i,ok := <- ch   
    if !ok {
        fmt.Printf("channel is closed\n")
        return
    }
    fmt.Printf("read %d from channel\n", i)
}
Run Code Online (Sandbox Code Playgroud)

输出:

read 2 from channel
channel is closed
channel is closed
Run Code Online (Sandbox Code Playgroud)

Playground上运行"从封闭频道阅读"

写入可能关闭的频道更复杂,因为如果您只是在频道关闭时尝试写,Go会感到恐慌:

//writing to closed channel

package main

import (
    "fmt"
)

func main() {
    output := make(chan int, 1) // create channel
    write(output, 2)
    close(output) // close channel
    write(output, 3)
    write(output, 4)
}

// how to write on possibly closed channel
func write(out chan int, i int) (err error) {

    defer func() {
        // recover from panic caused by writing to a closed channel
        if r := recover(); r != nil {
            err = fmt.Errorf("%v", r)
            fmt.Printf("write: error writing %d on channel: %v\n", i, err)
            return
        }

        fmt.Printf("write: wrote %d on channel\n", i)
    }()

    out <- i // write on possibly closed channel

    return err
}
Run Code Online (Sandbox Code Playgroud)

输出:

write: wrote 2 on channel
write: error writing 3 on channel: send on closed channel
write: error writing 4 on channel: send on closed channel
Run Code Online (Sandbox Code Playgroud)

Playground上运行"写入封闭频道"

据我所知,在没有恐慌的情况下写入可能封闭的频道并没有更简单的习惯用语.为什么不?读写之间这种不对称行为背后的原因是什么?

小智 16

来自Go语言规范:

对于通道c,内置函数close(c)记录将不再在通道上发送值.如果c是仅接收通道,则会出错.发送或关闭已关闭的通道会导致运行时出现紧急情况.关闭零通道也会导致运行时恐慌.在调用close之后,在收到任何先前发送的值之后,接收操作将返回通道类型的零值而不会阻塞.多值接收操作返回接收值以及信道是否关闭的指示.

如果你写一个封闭的频道,你的节目将会惊慌失措.如果你真的想要这样做,你可能会通过恢复来捕获这个错误,但是在你不知道你正在写入的频道是否打开的情况下,通常是程序中的错误的标志.

一些引言:

这是一个动机:

频道"关闭"实际上只是在频道上发送特殊值.这是一个特殊值,承诺不再发送任何值.尝试在通道关闭后在通道上发送值会引起恐慌,因为实际发送该值会违反close提供的保证.由于收盘只是一种特殊的发送方式,因此在通道关闭后也不允许发送.

这是另一个:

频道关闭的唯一用途是向读者发出信号,表示没有更多的价值要来.只有在存在单个值源或多个源协调时才有意义.没有合理的程序,其中多个goroutine在没有通信的情况下关闭通道.这意味着多个goroutine会知道没有更多值要发送 - 如果他们不通信,他们怎么能确定?

(伊恩兰斯泰勒)

-

这是另一个:

关闭频道会将其作为资源释放.关闭一个通道的次数与多次关闭文件描述符或多次释放已分配的内存块没有任何关系.这些行为意味着代码被破坏,这就是关闭封闭渠道引发恐慌的原因.

(Rob Pike)

-

来源:去设计细节理由问题 - 渠道关闭

  • @Sreram,您可以拥有多个频道,而不是在同一频道上拥有多个作者。然后关闭每个通道。在接收端,您可以使用选择在每个通道准备好时进行选择。 (2认同)