我需要向生成的Go进程发送几个MB。我按照https://gobyexample.com/spawning-processes处的说明进行操作,但我的数据太大,无法按此方式发送。我以为我可以将数据分块。这是我最终得到的代码:
doit := exec.Command("/bin/bash", "-c", cmd) // cmd reads stdin
doit_stdin,_ := doit.StdinPipe()
doit_stdout,_ := doit.StdoutPipe()
doit.Start()
go func() {
w := bufio.NewWriter(doit_stdin)
for i := 0; i < nchunks; i++ {
w.Write(input_data[chunk_begin[i]:chunk_begin[i+1]])
w.Flush()
}
doit_stdin.Close()
}()
rc,_ := ioutil.ReadAll(doit_stdout)
doit.Wait()
其中input_data
为[]byte
,chunk_begin
是其他地方计算的断点数组。一切正常。 cmd
获取发送给它的所有数据,检测EOF,发回结果并退出。 ReadAll
获取从cmd发回的所有信息。但是do it.Wait()
会阻止。我无法理解为什么doit.Wait
会阻止。
或者,如果有其他标准方式传输大量数据,那也没关系。我确实需要控制断点,因为数据具有内部结构。
非常感谢任何帮助。
答案 0 :(得分:0)
问题出在输入程序上。
cmd.Wait等待编写器完成。
通话doit.StdinPipe().Close()
不会影响作者,尽管我不得不承认我对此感到惊讶。
我炮制了一个例子来证明这一点;
package main
import (
"bufio"
"io/ioutil"
"math"
"os/exec"
)
func main() {
doit := exec.Command("/bin/bash", "-c", "md5sum")
doitStdin,_ := doit.StdinPipe()
doitStdout,_ := doit.StdoutPipe()
doit.Start()
inputData := generateCrapForever()
k32 := 33
nchunks := len(inputData) / k32
chunkBegin := make([]int, nchunks)
var i = 0
for i<nchunks {
chunkBegin[i] = i*k32
i++
}
go func() {
w := bufio.NewWriter(doitStdin)
for i := 0; i < nchunks-1; i++ {
last := int(math.Max(float64(chunkBegin[i+1]), float64(len(inputData))))
w.Write(inputData[chunkBegin[i]:last])
w.Flush()
}
doitStdin.Close()
}()
rc,_ := ioutil.ReadAll(doitStdout)
doit.Wait()
println(string(rc))
}
func generateCrapForever() []byte {
out, _ := exec.Command("dd", "if=/dev/urandom", "bs=10" ).Output()
return out
}
如果将generateCrapForever()替换为generateCrap(),则代码将起作用。但是,如果输入管道从不退出并且一直在写入,则cmd.Wait将永远不会停止,因为它正在等待输入管道完成。
func generateCrap() []byte {
out, _ := exec.Command("dd", "if=/dev/urandom", "bs=10", "count=33").Output()
return out
}
实际上,在此示例中,阻止代码为generateCrapforever()
,而不是cmd.Wait
。也许代码中发生了类似的事情?