为什么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
据我所知,在没有恐慌的情况下写入可能封闭的频道并没有更简单的习惯用法。为什么不?读写之间存在这种不对称行为背后的原因是什么?
答案 0 :(得分:14)
对于通道c,内置函数close(c)不再记录 值将在频道上发送。如果c是a则是错误的 仅接收频道。发送或关闭封闭的通道会导致a 运行时恐慌。关闭零通道也会导致运行时恐慌。 在调用close之后,以及之前发送的任何值之后 收到,接收操作将返回零值 频道的类型没有阻止。多值接收操作 返回一个接收的值以及是否指示 频道已关闭。
如果您写封闭频道,您的节目会惊慌失措。如果你真的想这样做,你可能会catch this error with recover,但是在你不知道你写的频道是否开放的情况下,这通常是程序中一个错误的标志。 / p>
一些引言:
这是一个动机:
频道&#34;关闭&#34;实际上只是一个特殊值的发送 渠道。这是一个特殊的价值,承诺没有更多的价值观 被发送。尝试在通道上发送值后 关闭会惊慌失措,因为实际发送的价值会违反 保证由close提供。因为收盘只是一种特殊的 发送后,频道关闭后也不允许发送。
这是另一个:
频道关闭的唯一用途是向读者发出信号 没有更多的价值。这只有在有时才有意义 单个值的来源,或多个来源协调时。那里 是多个goroutine关闭一个频道的合理程序 没有沟通。这意味着多个goroutines 会知道没有更多的价值要发送 - 他们怎么可能 确定他们是否进行沟通?
(伊恩兰斯泰勒)
-
这是另一个:
关闭频道会将其作为资源释放。它没有任何意义 关闭一个通道多次关闭文件 描述符多次,或释放已分配的内存块 多次。这样的行为意味着代码被破坏,这就是原因 关闭一个封闭的通道会引发恐慌。
(Rob Pike)
-