我在os.fork
和子进程/多处理模块中看到的大多数示例都展示了如何派生调用python脚本的新实例或一大块python代码。同时生成一组任意shell命令的最佳方法是什么?
我想,我可以使用subprocess.call
或其中一个Popen
命令并将输出传输到一个文件,我相信它会立即返回,至少是调用者。我知道这并不难,我只想弄清楚最简单,最恐怖的方式。
提前致谢
答案 0 :(得分:3)
对subprocess.Popen
的所有来电都会立即返回给来电者。这是对wait
和communicate
的调用阻止。因此,您需要做的就是使用subprocess.Popen
(将stdin设置为/ dev / null以确保安全性)启动多个进程,然后逐个调用communicate
直到它们全部完成。< / p>
当然,我假设你只是想尝试启动一堆不相关的(即没有管道连接)命令。
答案 1 :(得分:1)
我想,我可以只使用subprocess.call或其中一个Popen 命令并将输出传递给文件,我相信它会返回 立即,至少对来电者。
如果你想处理数据,这不是一个好方法。
在这种情况下,做得更好
sp = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
然后sp.communicate()
或直接从sp.stdout.read()
阅读。
如果以后在调用程序中处理数据,有两种方法:
您可以尽快检索数据,可以通过一个单独的线程,阅读它们并将它们存储在消费者可以获得它们的地方。
您可以让生成子流程具有块,并在需要时从中检索数据。子进程产生的数据与管道缓冲区中的数据一样多(通常为64 kiB),然后阻止进一步写入。只要您需要数据,就可以从子流程对象read()
(也可能是stdout
)stderr
并使用它们 - 或者再次使用{{1}在那个晚些时候。
如果生成数据需要很长时间,方法1就可以了,所以你的wprogram必须等待。
如果数据的大小非常庞大和/或数据产生得如此之快以至于缓冲毫无意义,那么第2种方式将是首选。
答案 2 :(得分:1)
我喜欢使用PTY而不是管道。对于我只想捕获错误消息的一堆进程,我做了这个。
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
循环,它收集了任何错误消息并将它们发送到单个日志文件。使用PTY意味着我从不必担心部分线条混乱,因为线条规则提供了简单的框架。
答案 3 :(得分:1)
在所有可能的情况下都没有最好的方法。最好的取决于手头的问题。
以下是如何生成进程并将其输出保存到组合stdout / stderr的文件中:
import subprocess
import sys
def spawn(cmd, output_file):
on_posix = 'posix' in sys.builtin_module_names
return subprocess.Popen(cmd, close_fds=on_posix, bufsize=-1,
stdin=open(os.devnull,'rb'),
stdout=output_file,
stderr=subprocess.STDOUT)
生成可以与脚本并行运行的多个进程:
processes, files = [], []
try:
for i, cmd in enumerate(commands):
files.append(open('out%d' % i, 'wb'))
processes.append(spawn(cmd, files[-1]))
finally:
for p in processes:
p.wait()
for f in files:
f.close()
注意:cmd
是一个无处不在的列表。
答案 4 :(得分:0)
请参阅an older answer of mine including code snippets:
为了生成多个并发命令,您需要更改类RunCmd以实例化多个读取输出/写入输入队列并生成多个Popen子进程。