同时将来自流的字节发送到两个目标

时间:2019-06-15 20:39:47

标签: go concurrency stream channel

从流同时向两个网络目标广播值的最佳方法是什么?这是简化的代码:

func main() {
    resp, _ := http.Get("http://origin.com/image.jpeg")

    var buf bytes.Buffer
    // tee, when read, writes to &buf
    respBodyTee := io.TeeReader(resp.Body, &buf)

    sendToClient(respBodyTee)
    uploadeToServer(&buf)
}

一个流不能被读取两次,因此TeeReader被用来从&buf读取的内容填充respo.Body

但是,函数(sendToClientuploadToServer)将同步运行,而我希望它们同时进行工作。

我想到的解决方案是将通道传递到sendToClient,该通道将使用已经发送到客户端的字节填充通道。以后,uploadToServer从同一频道读取。遵循以下原则:

func main() {
    resp, _ := http.Get("http://origin.com/image.jpeg")

    ch := make(chan byte)
    go sendToClient(respBodyTee, ch) // pass 'ch' for writing and run in a goroutine
    uploadeToServer(ch) // will read from 'ch' (synchronous)
}

我是Go的新手,不确定上面的方向是否正确。

1 个答案:

答案 0 :(得分:1)

在您的方案中,最好有2个独立的字节流来进行2个网络调用。如果它们依赖一个源流,则sendToClient停滞时uploadeToServer将挂起。通道无法解决上述问题,但会引入锁定开销。

您可以尝试io.MultiWriter制作2个独立的字节流

var buf1, buf2 bytes.Buffer
mw := io.MultiWriter(&buf1, &buf2)

if _, err := io.Copy(mw, r.Body); err != nil {
    ...
}
go sendToClient(buf1)
go uploadeToServer(buf2)
...