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

时间:2018-05-01 14:48:59

标签: go process pipe ipc

问题

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

问题

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

为什么不在goroutine或Linux上出现?

*** Golang参考使用goroutine描述Cmd.StdinPipe为an example,我的问题也已解决。这个问题源于对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.")
}

已验证的版本

  • go go go1.10.1 windows / amd64
  • go go go1.10.1 linux / amd64

2 个答案:

答案 0 :(得分:7)

如果管道中没有更多空间,则只写入块。虽然Windows中管道的大小可能是4k,但在Linux中要大得多。来自pipe(7)

  

...自Linux以来          2.6.11,系统中的管道容量为16页(即 65,536字节)          页面大小为4096字节)...

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

答案 1 :(得分:0)

这已经得到解答,如果您遇到此问题,可能需要使用的解决方法 - 请使用bufio包中提供的缓冲编写器。这使您可以使用可以完全控制的较大缓冲区来包装编写器。