Golang 深入理解io.Pipe同步通道

io.Pipe实现了一对多、多对多、多对一的内存数据通道功能,创建方式如下

func Pipe() (*PipeReader, *PipeWriter)

Pipe creates a synchronous in-memory pipe. It can be used to connect code expecting an io.Reader with code expecting an io.Writer.
Reads and Writes on the pipe are matched one to one except when multiple Reads are needed to consume a single Write. That is, each Write to the PipeWriter blocks until it has satisfied one or more Reads from the PipeReader that fully consume the written data. The data is copied directly from the Write to the corresponding Read (or Reads); there is no internal buffering.
It is safe to call Read and Write in parallel with each other or with Close. Parallel calls to Read and parallel calls to Write are also safe: the individual calls will be gated sequentially.

官方说明中重点提到不管是并行写入还是并行读取都是安全的。其次是pipe适用于多个读取按写入顺序消费单个写入数据的场景。每次写入数据后都将被阻塞直到数据被完整读取。最后是数据拷贝过程没有使用缓存。这看起来其实挺晦涩的,要真正理解还是得有具体场景。

io.Pipe类似餐厅点餐。虽然有多人点餐但点单系统会按照点餐顺序一道菜一道菜发送到厨房,且每次发送都是上一道菜完成之后。那么点单系统就是PipeWriter,每一次发送就是Write,为了方便理解对源代码进行了简化如下:

func (p *pipe) Write(b []byte) (n int, err error) {
    //写入锁,每次数据完整写入前其他并行写入将在此被阻塞
    p.wrMu.Lock()
    defer p.wrMu.Unlock()

    //循环写入直到完整写入
    for len(b) > 0 {
        //发送数据到p.wrCh,读取端将从p.wrCh中读取
        p.wrCh <- b
        //读取端单次读取的量
        nw := <-p.rdCh
        b = b[nw:]
        n += nw 
    }
    return n, nil
}

现在订单(鱼香茄子一份)进入厨房,厨师有好几个,每一个厨师就是PipeReader。第一个厨师看到(Read)”鱼”字,开始准备鱼。第二厨师看到”茄子”开始准备茄子。第三个厨师看到“一份”开始洗锅热锅。简化代码如下:

func (p *pipe) Read(b []byte) (n int, err error) {
    //接收p.wrCh中数据
    bw := <-p.wrCh
    //不完整读取量
    nr := copy(b, bw)   
    //读取量发送给写入端
    p.rdCh <- nr
    return nr, nil  
}

到此厨师不断处理订单,一道道菜按顺序完成。虽然官方说明中提到Pipe是一对多的通道。但从源码中可以看到写入是阻塞的,多对多的关系依然不会出现问题。当然需要注意多个读取存在拆分包的情况。也就是说每次写入都是一个不可分割的数据包时,那么多个读取虽然是线程安全的,但也会发生读取的数据不完整的情况。比如“鱼香茄子”只读取了鱼。要避免这种情况,要么是读取的缓存够大,要么就是多对一的方式,只有一个读取端。

最后,Pipe允许在并行的情况下关闭写入或读取。当任意一个写入或读取端调用Close函数后,其他线程都将立即返回已操作数据量和CloseError标记。这是非常大的一个优点。因为写入的是一个大数据块,分多次读取的中途被关闭。不管是写入端还是读取端都能获取到已处理的数据量。可以防止数据的丢失。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值