猿问

为什么 Go 在写入关闭的通道时会出现恐慌?

为什么 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)

}

输出:


read 2 from channel

channel is closed

channel is closed

在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

}

输出:


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

在Playground上运行“写入封闭频道”


据我所知,没有一个更简单的习惯用法可以在不惊慌的情况下写入可能已关闭的通道。为什么不?这种读写之间的不对称行为背后的原因是什么?


慕森王
浏览 148回答 1
1回答

泛舟湖上清波郎朗

从Go 语言规范:对于通道 c,内置函数 close(c) 记录不会在通道上发送更多值。如果 c 是只接收通道,这是一个错误。发送到或关闭关闭的通道会导致运行时恐慌。关闭 nil 通道也会导致运行时恐慌。在调用 close 之后,并且在接收到任何先前发送的值之后,接收操作将在不阻塞的情况下返回通道类型的零值。多值接收操作返回接收到的值以及通道是否关闭的指示。如果你写入一个封闭的通道,你的程序会崩溃。如果您真的想这样做,您可能会通过恢复来捕获此错误,但是处于不知道要写入的通道是否打开的情况通常是程序中存在错误的迹象。一些引用:这是一个动机:通道“关闭”实际上只是在通道上发送特殊值。这是一个特殊的值,承诺不会发送更多的值。尝试在关闭后在通道上发送值会导致恐慌,因为实际发送值会违反 close 提供的保证。由于关闭只是一种特殊的发送,因此在通道关闭后也是不允许的。这是另一个:通道关闭的唯一用途是向读者发出信号,表明没有更多的值出现。这仅在存在单一值来源或多个来源协调时才有意义。没有合理的程序可以让多个 goroutine 关闭一个通道而不进行通信。这意味着多个 goroutine 会知道没有更多的值要发送——如果它们不通信,它们如何确定呢?(伊恩·兰斯·泰勒)——这是另一个:关闭通道会将其作为资源释放。多次关闭通道并不比多次关闭文件描述符或多次释放分配的内存块更有意义。此类操作意味着代码已损坏,这就是关闭关闭的通道会触发恐慌的原因。(罗伯·派克)——
随时随地看视频慕课网APP

相关分类

Go
我要回答