我如何从Pythonasynchronous运行外部命令?

我需要从Python脚本asynchronous运行一个shell命令。 通过这个我的意思是我希望我的Python脚本能够在外部命令closures时继续运行,并执行任何需要的操作。

我读过这篇文章:

在Python中调用外部命令

然后,我去了,做了一些testing,它看起来像os.system()将做的工作,只要我在命令的末尾使用& ,以便我不必等待它返回。 我想知道的是,如果这是完成这样的事情的正确方法? 我尝试了commands.call()但它不会为我工作,因为它阻止外部命令。

请让我知道如果使用os.system()这是可取的,或者如果我应该尝试其他的路线。

subprocess.Popen正是你想要的。

 from subprocess import Popen p = Popen(['watch', 'ls']) # something long running # ... do other stuff while subprocess is running p.terminate() 

(编辑完成评论的答案)

Popen实例可以做其他各种各样的事情,比如你可以poll()它看看它是否还在运行,你可以和它communicate()在stdin上发送它的数据,并等待它终止。

如果要并行运行多个进程,然后在产生结果时处理它们,可以使用如下所示的轮询:

 from subprocess import Popen, PIPE import time running_procs = [ Popen(['/usr/bin/my_cmd', '-i %s' % path], stdout=PIPE, stderr=PIPE) for path in '/tmp/file0 /tmp/file1 /tmp/file2'.split()] while running_procs: for proc in running_procs: retcode = proc.poll() if retcode is not None: # Process finished. running_procs.remove(proc) break else: # No process is done, wait a bit and check again. time.sleep(.1) continue # Here, `proc` has finished with return code `retcode` if retcode != 0: """Error handling.""" handle_results(proc.stdout) 

控制stream程有一点点复杂,因为我试图让它变小 – 你可以重构你的口味。 🙂

这具有优先服务于早期完成请求。 如果您在第一次运行的进程中调用communicate ,结果运行时间最长,那么其他正在运行的进程将在您处理结果时处于空闲状态。

我想知道的是,如果这个[os.system()]是完成这样的事情的正确方法?

os.system()不是正确的方法。 这就是为什么每个人都说使用subprocess

有关更多信息,请阅读http://docs.python.org/library/os.html#os.system

子stream程模块提供了更多强大的工具来产生新的stream程和检索结果; 使用该模块比使用此function更可取。 使用子stream程模块。 请特别检查使用子stream程模块部分replace旧function。

使用pexpect [ http://www.noah.org/wiki/Pexpect ]与非阻塞readlines是另一种方法来做到这一点。 Pexpect解决了死锁问题,使您可以轻松地在后台运行进程,并且在您的进程吐出预定义的string时提供简单的callback方法,并且通常可以更轻松地与进程交互。

我用asyncproc模块获得了很好的成功,它很好地处理了进程的输出。 例如:

 import os from asynproc import Process myProc = Process("myprogram.app") while True: # check to see if process has ended poll = myProc.wait(os.WNOHANG) if poll is not None: break # print any new output out = myProc.read() if out != "": print out 

尝试使用Python中的s3270脚本软件连接到3270terminal时遇到同样的问题。 现在我正在解决与我在这里find的Process的子类的问题:

http://code.activestate.com/recipes/440554/

这里是从文件中取得的样本:

 def recv_some(p, t=.1, e=1, tr=5, stderr=0): if tr < 1: tr = 1 x = time.time()+t y = [] r = '' pr = p.recv if stderr: pr = p.recv_err while time.time() < x or r: r = pr() if r is None: if e: raise Exception(message) else: break elif r: y.append(r) else: time.sleep(max((x-time.time())/tr, 0)) return ''.join(y) def send_all(p, data): while len(data): sent = p.send(data) if sent is None: raise Exception(message) data = buffer(data, sent) if __name__ == '__main__': if sys.platform == 'win32': shell, commands, tail = ('cmd', ('dir /w', 'echo HELLO WORLD'), '\r\n') else: shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n') a = Popen(shell, stdin=PIPE, stdout=PIPE) print recv_some(a), for cmd in commands: send_all(a, cmd + tail) print recv_some(a), send_all(a, 'exit' + tail) print recv_some(a, e=0) a.wait() 

考虑到“我不必等它回来”,最简单的解决scheme之一就是:

 subprocess.Popen( \ [path_to_executable, arg1, arg2, ... argN], creationflags = subprocess.CREATE_NEW_CONSOLE, ).pid 

但是…从我读到的这个不是“完成这样的事情的正确方法”,因为subprocess.CREATE_NEW_CONSOLE产生的安全风险subprocess.CREATE_NEW_CONSOLE标志。

在这里发生的关键是使用.pid来创build新的控制台和.pid (返回进程ID,以便您可以稍后检查程序,如果你想),以便不等待程序完成它的工作。