向 exec.Cmd.StdinPipe() 写入超过 4K 字节
Write more than 4K bytes to exec.Cmd.StdinPipe()
问题
在 Go 中将超过 4096 字节的数据写入 Cmd.StdinPipe
时,程序处理停止在 Windows。在Linux上运行或者使用goroutine写进程时不会出现这种现象。
问题
处理将不会从下面显示的代码中的 _, err = in.Write ([] byte {'0'})
(4097 字节)开始。这是为什么?
为什么它不会出现在 goroutine 或 Linux 上?
*** Golang参考文献描述Cmd.StdinPipe使用goroutine为an example,我的问题也解决了。这个问题源于对围棋的好奇。
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版本go1.10.1windows/amd64
- go版本go1.10.1linux/amd64
如果管道中不再有 space,则只写入块。虽然 Windows 中的管道大小可能是 4k,但在 Linux 中要大得多。来自 pipe(7):
... Since Linux
2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a system
with a page size of 4096 bytes)...
因此,当写入没有人正在读取的管道时,您可能会在 Linux 上获得与在 Windows 上相同的结果,但您需要向管道中写入更多数据,直到您到达这种情况。
这已经得到解答,如果您 运行 遇到此问题,您可能想使用以下解决方法 - 请改用 bufio 包中提供的缓冲编写器。这使您可以使用您可以完全控制的更大缓冲区来包装编写器。
问题
在 Go 中将超过 4096 字节的数据写入 Cmd.StdinPipe
时,程序处理停止在 Windows。在Linux上运行或者使用goroutine写进程时不会出现这种现象。
问题
处理将不会从下面显示的代码中的 _, err = in.Write ([] byte {'0'})
(4097 字节)开始。这是为什么?
为什么它不会出现在 goroutine 或 Linux 上?
*** Golang参考文献描述Cmd.StdinPipe使用goroutine为an example,我的问题也解决了。这个问题源于对围棋的好奇。
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版本go1.10.1windows/amd64
- go版本go1.10.1linux/amd64
如果管道中不再有 space,则只写入块。虽然 Windows 中的管道大小可能是 4k,但在 Linux 中要大得多。来自 pipe(7):
... Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a system with a page size of 4096 bytes)...
因此,当写入没有人正在读取的管道时,您可能会在 Linux 上获得与在 Windows 上相同的结果,但您需要向管道中写入更多数据,直到您到达这种情况。
这已经得到解答,如果您 运行 遇到此问题,您可能想使用以下解决方法 - 请改用 bufio 包中提供的缓冲编写器。这使您可以使用您可以完全控制的更大缓冲区来包装编写器。