使用Go的exec.Command通过管道读取数据时程序挂起问题
问题原因及解决方法
核心问题
程序挂起的主因是Python的输出缓冲机制:当Python的stdout不是终端(比如被Go的管道捕获)时,print默认采用块缓冲模式,不会立即将输出内容写入stdout管道,导致Go端的ReadLine()一直阻塞等待数据。
同时你的Go代码存在两处细节问题:
- 未正确处理
ReadLine()的返回值,直接打印buf(这是Reader对象,而非读取到的内容) - 写完stdin后未关闭管道,Python的
for line in sys.stdin会持续等待更多输入(虽非本次挂起的主因,但会导致进程无法正常退出)
解决步骤
1. 修改Python脚本,强制刷新输出
给print添加flush=True参数,让输出立即写入管道:
import sys if __name__=='__main__': for line in sys.stdin: print("Hello", line.strip(), flush=True)
也可以在print后手动调用刷新:
import sys if __name__=='__main__': for line in sys.stdin: print("Hello", line.strip()) sys.stdout.flush()
2. 修正Go代码的细节问题
处理ReadLine()的返回值,写完stdin后关闭管道(无需持续通信时),并等待命令执行完成避免僵尸进程:
package main import ( "bufio" "log" "os/exec" ) func main() { cmd := exec.Command("python3", "app.py") stdout, err := cmd.StdoutPipe() if err != nil { log.Fatal(err) } stdin, err := cmd.StdinPipe() if err != nil { log.Fatal(err) } if err := cmd.Start(); err != nil { log.Fatal(err) } _, err = stdin.Write([]byte("Bob\n")) if err != nil { log.Fatal(err) } // 关闭stdin,告知Python输入结束 if err := stdin.Close(); err != nil { log.Fatal(err) } buf := bufio.NewReader(stdout) line, _, err := buf.ReadLine() if err != nil { log.Fatal(err) } log.Println(string(line)) // 等待命令执行完成 if err := cmd.Wait(); err != nil { log.Fatal(err) } }
额外说明
若需要和Python程序保持持续双向通信,不要关闭stdin,但需确保Python端每次输出都主动刷新,同时Go端要实现循环读写的逻辑。
内容的提问来源于stack exchange,提问作者poundifdef
相关产品推荐
相关产品推荐

