1 回答

TA貢獻2016條經驗 獲得超9個贊
嘗試這樣的事情(下面的解釋):
package main
import (
? ? "fmt"
? ? "io"
? ? "io/ioutil"
? ? "log"
? ? "mime/multipart"
? ? "os"
? ? "os/exec"
? ? "sync"
? ? "github.com/pkg/errors"
)
func readCommand(cmdStdout io.ReadCloser, wg *sync.WaitGroup, resc chan<- []byte, errc chan<- error) {
? ? defer wg.Done()
? ? defer close(errc)
? ? defer close(resc)
? ? mr := multipart.NewReader(cmdStdout, "foo")
? ? for {
? ? ? ? part, err := mr.NextPart()
? ? ? ? if err != nil {
? ? ? ? ? ? if err == io.EOF {
? ? ? ? ? ? ? ? fmt.Println("EOF")
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? errc <- errors.Wrap(err, "failed to get next part")
? ? ? ? ? ? }
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? slurp, err := ioutil.ReadAll(part)
? ? ? ? if err != nil {
? ? ? ? ? ? errc <- errors.Wrap(err, "failed to read part")
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? resc <- slurp
? ? }
}
func main() {
? ? cmd := exec.Command("python", "output.py")
? ? cmd.Stderr = os.Stderr
? ? pr, err := cmd.StdoutPipe()
? ? if err != nil {
? ? ? ? log.Fatal(err)
? ? }
? ? var wg sync.WaitGroup
? ? wg.Add(1)
? ? resc := make(chan []byte)
? ? errc := make(chan error)
? ? go readCommand(pr, &wg, resc, errc)
? ? if err := cmd.Start(); err != nil {
? ? ? ? log.Fatal(err)
? ? }
? ? for {
? ? ? ? select {
? ? ? ? case err, ok := <-errc:
? ? ? ? ? ? if !ok {
? ? ? ? ? ? ? ? errc = nil
? ? ? ? ? ? ? ? break
? ? ? ? ? ? }
? ? ? ? ? ? if err != nil {
? ? ? ? ? ? ? ? log.Fatal(errors.Wrap(err, "error from goroutine"))
? ? ? ? ? ? }
? ? ? ? case res, ok := <-resc:
? ? ? ? ? ? if !ok {
? ? ? ? ? ? ? ? resc = nil
? ? ? ? ? ? ? ? break
? ? ? ? ? ? }
? ? ? ? ? ? fmt.Printf("Part from goroutine: %q\n", res)
? ? ? ? }
? ? ? ? if errc == nil && resc == nil {
? ? ? ? ? ? break
? ? ? ? }
? ? }
? ? cmd.Wait()
? ? wg.Wait()
}
排名不分先后:
與其使用 an
io.Pipe()
作為命令的Stdout
,不如向命令詢問它的StdoutPipe()
。cmd.Wait()
將確保它為您關閉。設置
cmd.Stderr
為os.Stderr
以便您可以查看 Python 程序生成的錯誤。我注意到只要 Python 程序寫入標準錯誤,這個程序就會掛起。現在它沒有:)
不要將其設為
WaitGroup
全局變量;將對它的引用傳遞給 goroutine。與其
log.Fatal()
在 goroutine 內部執行 ing,不如創建一個錯誤通道來將錯誤傳回給main()
.與其在 goroutine 中打印結果,不如創建一個結果通道將結果傳回給
main()
.確保通道關閉以防止阻塞/goroutine 泄漏。
將 goroutine 分離到一個適當的函數中,使代碼更易于閱讀和遵循。
在這個例子中,我們可以在我們的 goroutine 內部創建
multipart.Reader()
,因為這是我們代碼中唯一使用它的部分。請注意,我使用
Wrap()
fromerrors
包來為錯誤消息添加上下文。當然,這與您的問題無關,但這是一個好習慣。
該for { select { ... } }
部分可能令人困惑。
- 1 回答
- 0 關注
- 173 瀏覽
添加回答
舉報