• 简体中文
  • Example: io.Pipe

    简明示例

    io.Pipe 在内存中架设一条数据同步通道,它会同时返回一个读取端(io.PipeReader)和一个写入端(io.PipeWriter)。任何写入到 Writer 的数据,都可以立刻从 Reader 中读出,非常适合用来解耦“只负责写数据”和“只负责读数据”的两个独立业务逻辑。

    常见的生产环境应用场景:

    • 流式压缩管道:边读边压缩,不用等整个文件处理完;
    • 生成文件直传存储:数据生成后直接推送到对象存储(比如 S3),不落盘;
    • 串联编码器与网络写入器:把编码逻辑和网络发送无缝对接起来;
    • 处理海量数据流:全程内存操作,完全不需要依赖临时文件。

    下面示例中,协程把数据写入io.PipeWriter,io.Copy把数据从io.PipeReader搬运到标准输出。

    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func main() {
    
        // 1. 初始化管道,返回读端 r 和写端 w
    
        r, w := io.Pipe()
    
        // 2. 必须启动一个独立的协程(goroutine)去写入数据
    
        // 因为 io.Pipe 没有内置缓冲区,写端会一直阻塞,直到读端开始读取
    
        go func() {
            // 写入完成后必须关闭写端,否则读端会无限等待
            defer w.Close()
    
            fmt.Fprint(w, "Hello, io.Pipe from gobase.net.\n")
    
        }()
    
        // 3. 在主协程中消费数据,这里直接将管道读端的数据拷贝到标准输出
    
        _, err := io.Copy(os.Stdout, r)
    
        if err != nil {
    
            fmt.Fprintf(os.Stderr, "读取管道时发生错误: %v\n", err)
    
            return
        }
    
    }

    输出

    Hello, io.Pipe from gobase.net.
    
    无缓冲的同步阻塞特性

    io.Pipe 内部是完全没有缓冲区的,它的数据传输属于“直接交付”:

    • 单协程死锁:绝对不能在同一个协程里先后执行 w.Write()r.Read()。由于没有缓冲区,写入操作会瞬间卡死,导致程序报死锁错误。
    • 主动传递错误:如果写端在生成数据时发生了异常,可以使用 w.CloseWithError(err) 代替普通的 Close()。这样读端在消费完剩余数据后,接下来的读取操作会直接收到你指定的这个 err,非常便于跨协程传递业务错误。