在Python中分叉多个shell命令/进程的最佳方法是什么?
我看到的大多数关于 os.fork
和 subprocess/multiprocessing 模块的例子,都是在讲如何复制一个新的 Python 脚本实例或者一段 Python 代码。那有没有什么好的方法可以同时运行一组任意的 shell 命令呢?
我想,我可以直接使用 subprocess.call
或者某个 Popen
命令,然后把输出结果写入一个文件。我觉得这样做会很快返回结果,至少对调用者来说是这样的。我知道这并不难,我只是想找出最简单、最符合 Python 风格的方法来实现。
提前谢谢你们!
5 个回答
我喜欢用伪终端(PTYs)来代替管道。对于一些我只想捕捉错误信息的进程,我是这么做的。
RNULL = open('/dev/null', 'r')
WNULL = open('/dev/null', 'w')
logfile = open("myprocess.log", "a", 1)
REALSTDERR = sys.stderr
sys.stderr = logfile
接下来的部分是在一个循环中启动大约30个进程。
sys.stderr = REALSTDERR
master, slave = pty.openpty()
self.subp = Popen(self.parsed, shell=False, stdin=RNULL, stdout=WNULL, stderr=slave)
sys.stderr = logfile
之后我有一个select
循环,用来收集任何错误信息,并把它们发送到一个单独的日志文件。使用伪终端的好处是,我不用担心行内容会混在一起,因为行的管理方式让每一行都很清晰。
我想,我可以直接用subprocess.call或者Popen命令,把输出结果导入到一个文件里,这样应该会立刻返回结果,至少对调用者来说是这样的。
不过,如果你想处理这些数据,这样做就不太合适了。
在这种情况下,最好是这样做:
sp = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
然后可以用sp.communicate()
或者直接从sp.stdout.read()
读取数据。
如果你打算在后面某个时间处理这些数据,有两种方法可以选择:
你可以尽快获取数据,可能通过一个单独的线程来读取数据,并把它存储在某个地方,方便后续使用。
你也可以让生成数据的子进程阻塞,等到你需要数据时再从它那里获取。这个子进程会尽量把数据写入管道缓冲区(通常是64KB),然后在写入更多数据时会阻塞。只要你需要数据,就可以从子进程的
stdout
(也可能是stderr
)中read()
,然后使用这些数据——或者在稍后的时间再次使用sp.communicate()
。
如果生成数据需要很长时间,第一种方法比较合适,这样你的程序就不需要一直等待。
如果数据量很大,或者数据生成得非常快,以至于缓冲没有意义,那么第二种方法更为推荐。
所有对 subprocess.Popen
的调用都会立即返回给调用者,也就是说,当你启动一个新进程时,程序不会停下来等这个进程完成。而是要等你调用 wait
或 communicate
时,程序才会暂停,等这些进程完成。所以,你只需要用 subprocess.Popen
启动多个进程(为了安全,输入可以设置为 /dev/null),然后一个一个地调用 communicate
,直到所有进程都完成。
当然,我假设你只是想启动一堆没有关系的(也就是不相互连接的)命令。