写入超过4K字节的exec.Cmd.StdinPipe()

1 ipc pipe process go

问题

Cmd.StdinPipe在Go中写入超过4096字节的数据时,程序处理在Windows上停止.当在Linux上运行相同的代码或使用goroutine编写进程时,不会发生这种现象.

处理不会从_, err = in.Write ([] byte {'0'})下面显示的代码中的(4097字节)开始.为什么是这样?

为什么不在goroutine或Linux上发生?

***Golang参考使用goroutine作为示例描述了Cmd.StdinPipe ,我的问题也已经解决了.这个问题源于对Go的好奇心.

package main

import (
    "bytes"
    "fmt"
    "io"
    "log"
    "os/exec"
)

func main() {
    cmd := exec.Command("more")

    pype, err := cmd.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }

    bytes4k := generateBytes(1024 * 4) // Works on Linux, but not Windows.
    // bytes4k := generateBytes(1024 * 64) // Don't works on Linux and Windows.
    fmt.Println("bytes generated.")

    // go writeBytes(pype, bytes4k) // Works fine!
    writeBytes(pype, bytes4k) // Can't write. Write is locked.

    err = cmd.Run()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("finished.")
}

func generateBytes(num int) []byte {
    byte := bytes.NewBuffer(make([]byte, 0, num))
    for i := 0; i < num; i++ {
        byte.WriteByte('0')
    }
    return byte.Bytes()
}

func writeBytes(in io.WriteCloser, bytes []byte) {
    defer in.Close()

    _, err := in.Write(bytes)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("written bytes to pipe.")

    _, err = in.Write([]byte{'0'}) // Why this code stops at 4097 bytes?
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("written 1 byte to pipe.")
}
Run Code Online (Sandbox Code Playgroud)

验证版本

  • 去版本go1.10.1 windows/amd64
  • 去版本go1.10.1 linux/amd64

Ste*_*ich 7

如果管道中没有更多空间,则仅写入块.虽然Windows中管道的大小可能是4k,但在Linux中要大得多.从管道(7):

...从Linux 2.6.11开始,管道容量为16页(即,在一个页面大小为4096字节的系统中为65,536字节)...

因此,当你写入没有人正在读取的管道时,你可能会在Linux上得到与在Windows上相同的结果,但是在你遇到这种情况之前,你需要将更多数据写入管道.