【发布时间】:2016-03-07 21:46:32
【问题描述】:
我有一个函数,它返回 io.Pipe 的 Reader 端并启动一个 go-routine,它将数据写入它的 Writer 端,然后关闭管道。
func GetPipeReader() io.ReadCloser {
r, w := io.Pipe()
go func() {
_, err := io.CopyN(w, SomeReaderOfSize(N), N)
w.CloseWithError(err)
}()
return r
}
func main() {
var buf bytes.Buffer
io.Copy(&buf, GetPipeReader())
println("got", buf.Len(), "bytes")
}
https://play.golang.org/p/OAijIwmtRr
这似乎在我的测试中总是有效的,因为我得到了我写的所有数据。但是API docs 让我有点担心:
func Pipe() (*PipeReader, *PipeWriter)
Pipe 创建一个同步的内存管道。 [...] 一端的读数是 与另一方面的写入相匹配,[...] 没有内部 缓冲。
func (w *PipeWriter) CloseWithError(err error) 错误
CloseWithError 关闭写入器;读取一半的后续读取 的管道将不返回任何字节和错误 err,或者如果 err 是 EOF 无。
我想知道的是,这里可能的竞争条件是什么?我的 go-routine 会写入一堆数据,然后在我可以全部读取之前关闭管道,这是否合理?
我是否需要使用通道来发出一些关于何时关闭的信号?基本上会出什么问题。
【问题讨论】:
-
文档提到“可以安全地同时调用 Read 和 Write 或关闭。一旦挂起的 I/O 完成,关闭将完成”,所以我看不出哪里可以一场比赛发生了。
-
别担心,在比赛检测器下运行代码:-)。请注意,读取和写入是匹配的:您写入的数据被在您写入的那一刻被读取。只是在关闭删除数据后读取。只需确保读取确实消耗了您想要写入的所有内容。
-
种族检测器?!太棒了,我没有意识到there was such a thing。现在来看看。我稍后会玩它。
标签: go io race-condition