我有一个很长的io.Reader
每隔几秒钟返回一些数据(从不EOF),还有一个goroutine从该读者到io.Copy
执行bytes.Buffer
(也永远不会终止) )。像这样:
var src io.Reader
var buf bytes.Buffer
func main() {
go io.Copy(&buf, src)
// Do stuff. Read from the buffer periodically.
}
我不明白的是,当我尝试从缓冲区读取时,我看到了奇怪的结果。无论我是打电话给buf.Bytes()
还是ioutil.ReadAll(&buf)
还是其他什么都没关系,我只是看到一遍又一遍地写入缓冲区的第一个字节。
https://play.golang.org/p/yn0JPrvohV
我的问题是,我做错了什么?我可以这样使用bytes.Buffer
(io.Copy
并定期阅读吗?
答案 0 :(得分:1)
您无法将您的阅读调用与bytes.Buffer
中io.Copy
上发生的写入同步。即使将bytes.Buffer
包装在一个结构中以锁定读/写方法,当Read等待Read时,你将会发生死锁,而ReadAll在Read上被阻止。您需要手动执行复制,并正确序列化所有访问权限,或使用io.Pipe
分隔读取和写入。
如果您使用FIFO(io.Pipe
)来同步读取和写入,则不需要任何额外的锁定或通道来拖尾第一个io.Reader
。这是一个示例read
函数,可以在其缓冲区已满时打印,或者等待自上一个print语句以来的某个时间间隔:
func read(r io.Reader) {
buf := make([]byte, 1024)
pos := 0
lastPrint := time.Now()
for {
n, err := r.Read(buf[pos:])
if n > 0 {
pos += n
}
if pos >= len(buf) || time.Since(lastPrint) > 125*time.Millisecond && pos > 0 {
fmt.Println("read:", buf[:pos])
lastPrint = time.Now()
pos = 0
}
if err != nil {
fmt.Println(err)
break
}
}
if pos > 0 {
fmt.Println("read:", buf[:pos])
}
}
func main() {
pr, pw := io.Pipe()
go func() {
io.Copy(pw, &trickle{})
pw.Close()
}()
read(pr)
}