实时读取/写入子进程的stdin/stdout

3 投票
2 回答
552 浏览
提问于 2025-04-28 00:37

我想为另一个命令行程序做一个Python的封装。

我的目标是尽可能快地读取Python的 stdin(标准输入),对它进行过滤和转换,然后迅速写入到子程序的 stdin

同时,我也想尽量快地从子程序的 stdout(标准输出)读取数据,经过一些处理后,迅速写入到Python的 stdout

Python的子进程模块有很多警告,建议使用 communicate() 来避免死锁问题。但是,使用 communicate() 的话,我要等子程序结束后才能访问它的 stdout

暂无标签

2 个回答

1

免责声明:这个解决方案可能需要你能访问到你想要调用的进程的源代码,但即使如此,尝试一下也许是值得的。这取决于被调用的进程是否定期清空它的 stdout 缓冲区,而这并不是标准做法。

假设你有一个通过 subprocess.Popen 创建的进程 proc。这个 proc 有两个属性,分别是 stdinstdout。这些属性其实就是像文件一样的对象。所以,要通过 stdin 发送信息,你可以调用 proc.stdin.write()。要从 proc.stdout 获取信息,你可以调用 proc.stdout.readline() 来读取一行内容。

几点注意事项:

  • 当你通过 write()proc.stdin 写入内容时,记得在输入的最后加一个换行符。如果没有换行符,你的子进程会一直卡在那里,直到你输入一个换行符。
  • 要从 proc.stdout 读取信息,你需要确保子进程调用的命令在每次打印后都能正确清空它的 stdout 缓冲区,并且每一行的末尾都有换行符。如果 stdout 缓冲区没有在合适的时机被清空,你调用 proc.stdout.readline() 时也会卡住。
1

我觉得你可以小心地忽略那些警告,自己使用 Popen.stdin 等等。只要确保逐行处理这些数据流,并且合理安排处理的时间,这样就不会让任何缓冲区满了。在Python中,有一种相对简单(但效率不高)的方法,就是为这三个数据流使用不同的线程。这就是 Popen.communicate 在内部处理的方式。你可以看看它的源代码,了解具体是怎么做的。

撰写回答