Go为什么要写封闭频道?

时间:2016-01-20 10:45:30

标签: go concurrency channel goroutine panic

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

运行&#34;从封闭频道阅读&#34;在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

运行&#34;写入封闭频道&#34;在Playground

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

1 个答案:

答案 0 :(得分:14)

来自Go Language Spec

  

对于通道c,内置函数close(c)不再记录   值将在频道上发送。如果c是a则是错误的   仅接收频道。发送或关闭封闭的通道会导致a   运行时恐慌。关闭零通道也会导致运行时恐慌。   在调用close之后,以及之前发送的任何值之后   收到,接收操作将返回零值   频道的类型没有阻止。多值接收操作   返回一个接收的值以及是否指示   频道已关闭。

如果您写封闭频道,您的节目会惊慌失措。如果你真的想这样做,你可能会catch this error with recover,但是在你不知道你写的频道是否开放的情况下,这通常是程序中一个错误的标志。 / p>

一些引言:

  

这是一个动机:

     

频道&#34;关闭&#34;实际上只是一个特殊值的发送   渠道。这是一个特殊的价值,承诺没有更多的价值观   被发送。尝试在通道上发送值后   关闭会惊慌失措,因为实际发送的价值会违反   保证由close提供。因为收盘只是一种特殊的   发送后,频道关闭后也不允许发送。

     

这是另一个:

     

频道关闭的唯一用途是向读者发出信号   没有更多的价值。这只有在有时才有意义   单个值的来源,或多个来源协调时。那里   是多个goroutine关闭一个频道的合理程序   没有沟通。这意味着多个goroutines   会知道没有更多的价值要发送 - 他们怎么可能   确定他们是否进行沟通?

     

(伊恩兰斯泰勒)

-

  

这是另一个:

     

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

     

(Rob Pike)

-

来源:Go design detail rationale question - channel close