Go语言:向生成的进程发送数据时,Wait()不返回

时间:2016-08-09 13:14:42

标签: go

我需要向生成的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[]bytechunk_begin是其他地方计算的断点数组。一切正常。 cmd获取发送给它的所有数据,检测EOF,发回结果并退出。 ReadAll获取从cmd发回的所有信息。但是do it.Wait()会阻止。我无法理解为什么doit.Wait会阻止。

或者,如果有其他标准方式传输大量数据,那也没关系。我确实需要控制断点,因为数据具有内部结构。

非常感谢任何帮助。

1 个答案:

答案 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。也许代码中发生了类似的事情?