阻塞和非阻塞子进程调用

92

我完全不清楚subprocess.call(), subprocess.Popen(), subprocess.check_call()之间的区别。

哪个是阻塞的,哪个不是?

我的意思是,如果我使用subprocess.Popen(),父进程是否会在继续执行之前等待子进程return/exit

shell=True如何影响这些调用?


你试过使用 subprocess.call([cmd,params,&]) 吗? - Charlie Parker
@CharlieParker,“&”必须用引号括起来,而“params”必须是列表的单独元素,并且必须使用“shell=True”,实际上应该使用字符串而不是预解析的列表。它确实可以工作,但这是一种hack方法。 - Karl Knechtel
1个回答

127

Popen是非阻塞的。callcheck_call是阻塞的。 您可以调用其waitcommunicate方法使Popen实例阻塞。

如果您查看源代码,您会看到call调用了Popen(...).wait(),这就是为什么它是阻塞的原因。 check_call调用call,这也是为什么它被阻塞的原因。

严格来说,shell=True与阻塞问题无关。但是,shell=True会导致Python执行一个外壳并在外壳中运行命令。如果您使用阻塞调用,则该调用将在外壳完成时返回。由于外壳可能会生成子进程来运行命令,因此外壳可能在生成的子进程之前完成。例如:

import subprocess
import time

proc = subprocess.Popen('ls -lRa /', shell=True)
time.sleep(3)
proc.terminate()
proc.wait()

这里会生成两个进程:Popen生成一个运行shell的子进程,而shell又生成一个运行ls的子进程。proc.terminate()杀死了shell,但是运行ls的子进程仍在运行(即使Python脚本已经结束,仍会有大量输出。准备好用pkill ls来杀死ls)。


6
start_new_session=True 或类似的参数能够一次性终止整个进程树。请参考如何终止使用shell=True启动的Python子进程 - jfs
2
@dorslash:如果命令来自用户输入,则shell=True可能会成为安全隐患。因此,最好尽可能使用shell=False。使用shell=False,在列表中提供命令及其参数:proc = subprocess.Popen(['/run_python.py', '-n', '10'], shell=False) - unutbu
2
@dotslash:Popen 始终是非阻塞的。它调用 waitcommunicate 会阻塞。 - unutbu
1
使用 subprocess.call([cmd,params,&]) 有什么问题?即添加标准的 & - Charlie Parker
3
如果我想使用 shell=True 并希望它阻塞执行,直到 shell 内部进程结束,我该怎么做? - Yuval Zilber
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接