dongwoqin7034 2016-11-27 21:44
浏览 44
已采纳

长时间运行的副本到bytes.Buffer

I have a long lived io.Reader which returns some data every few seconds (never EOF), and a goroutine which does an io.Copy from that reader to a bytes.Buffer (also never terminates). Something like so:

var src io.Reader
var buf bytes.Buffer

func main() {
    go io.Copy(&buf, src)
    // Do stuff. Read from the buffer periodically.
}

What I don't understand is that I see strange results when I try to read from that buffer. It doesn't matter whether I call buf.Bytes() or ioutil.ReadAll(&buf) or anything, I just see the first bytes written to the buffer over and over again.

https://play.golang.org/p/yn0JPrvohV

My question is, what am I doing wrong? Can I use bytes.Buffer in this way (io.Copy to it and read periodically)?

  • 写回答

1条回答 默认 最新

  • dqy92287 2016-11-28 18:37
    关注

    You can't synchronize your Read calls with the writes that are happening on the bytes.Buffer in the io.Copy. Even if you wrap the bytes.Buffer in a struct to lock the Read/Write methods, you are going to deadlock when the Copy is waiting on a Write while the ReadAll is blocked on the Read. You either need to do the copy manually, and properly serialize all access, or separate the reads and writes with an io.Pipe.

    If you use a FIFO (io.Pipe) to synchronize reads and writes, you don't need any extra locks or channels to tail the first io.Reader. Here's an example read function that either prints when its buffer is full, or waits some interval since the last print statement:

    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)
    }
    

    https://play.golang.org/p/8NeV3v0LOU

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?