Python Popen等待子进程,即使直接子进程已终止

Python Popen等待子进程,即使直接子进程已终止,python,subprocess,popen,Python,Subprocess,Popen,我正在Windows8/XP上使用Python2.7 我有一个程序a,它使用以下代码运行另一个程序B: p = Popen(["B"], stdout=PIPE, stderr=PIPE) stdout, stderr = p.communicate() return B运行一个批处理脚本C是一个长时间运行的脚本,我希望B退出,即使C还没有完成。我使用以下代码(在B中)完成了此操作: 当我运行B时,它会按预期工作。然而,当我运行A时,我希望它在B退出时退出。但A会等到C退出,即使B已经退出。对

我正在Windows8/XP上使用Python2.7

我有一个程序a,它使用以下代码运行另一个程序B:

p = Popen(["B"], stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
return
B运行一个批处理脚本C是一个长时间运行的脚本,我希望B退出,即使C还没有完成。我使用以下代码(在B中)完成了此操作:

当我运行B时,它会按预期工作。然而,当我运行A时,我希望它在B退出时退出。但A会等到C退出,即使B已经退出。对正在发生的事情和可能的解决方案有什么想法吗

不幸的是,将A改成B的明显解决方案不是一个选项

以下是说明此问题的函数示例代码:


非常感谢您的任何输入。

您可以为
C
子流程提供
start\u new\u session
模拟:

#!/usr/bin/env python
import os
import sys
import platform
from subprocess import Popen, PIPE

# set system/version dependent "start_new_session" analogs
kwargs = {}
if platform.system() == 'Windows':
    # from msdn [1]
    CREATE_NEW_PROCESS_GROUP = 0x00000200  # note: could get it from subprocess
    DETACHED_PROCESS = 0x00000008          # 0x8 | 0x200 == 0x208
    kwargs.update(creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)  
elif sys.version_info < (3, 2):  # assume posix
    kwargs.update(preexec_fn=os.setsid)
else:  # Python 3.2+ and Unix
    kwargs.update(start_new_session=True)

p = Popen(["C"], stdin=PIPE, stdout=PIPE, stderr=PIPE, **kwargs)
assert not p.poll()
#/usr/bin/env python
导入操作系统
导入系统
导入平台
从子流程导入Popen、PIPE
#设置与系统/版本相关的“启动新会话”模拟
kwargs={}
如果platform.system()=“Windows”:
#来自msdn[1]
创建新流程组=0x00000200注意:可以从子流程获取
分离的_进程=0x00000008#0x8 | 0x200==0x208
更新(creationflags=Distached_PROCESS | CREATE_NEW_PROCESS_GROUP)
elif sys.version_info<(3,2):#假设posix
kwargs.update(preexec_fn=os.setsid)
其他:#Python 3.2+和Unix
kwargs.update(start\u new\u session=True)
p=Popen([“C”],标准输入=管道,标准输出=管道,标准输出=管道,**kwargs)
assert not p.poll()

[1] :

下面是一段代码片段,改编自塞巴斯蒂安的答案和答案:

#/usr/bin/env python
导入操作系统
导入系统
导入平台
从子流程导入Popen、PIPE
#设置与系统/版本相关的“启动新会话”模拟
kwargs={}
如果platform.system()=“Windows”:
#来自msdn[1]
创建新流程组=0x00000200注意:可以从子流程获取
分离的_进程=0x00000008#0x8 | 0x200==0x208
update(creationflags=Distached_PROCESS | CREATE_NEW_PROCESS_GROUP,close_fds=True)
elif sys.version_info<(3,2):#假设posix
kwargs.update(preexec_fn=os.setsid)
其他:#Python 3.2+和Unix
kwargs.update(start\u new\u session=True)
p=Popen([“C”],标准输入=管道,标准输出=管道,标准输出=管道,**kwargs)
assert not p.poll()

我只在Windows上亲自测试过它。

如果我做对了,你有运行程序B的程序Am,运行程序C。程序A也运行程序C。这正确吗?不,程序A不直接运行程序C。如果您看一下附件中的示例,那就太好了。谢谢。那么第二个
Popen
来自程序B?是的。A只运行B,与C没有直接关系。是否向第二个
Popen()调用帮助?我猜C从A继承了stdout/stderr管道,因此A会等到C关闭它们。成功地使用此代码创建了进程组(但没有DETACHED_进程标志)和psutil来终止进程树(即组):这仅适用于我在windows上使用
close\u fds=True
到windows
kwargs
行:
kwargs.update(creationflags=DETACHED\u PROCESS | CREATE\u NEW\u PROCESS\u GROUP,close\u fds=True)
(请参阅)@jtpreyda您是否注意到,如果重定向任何stdin、stdout、stderr?@J.F.Sebastian是的,我解释为,如果您使用
close\u fds=True
,则无法在Windows上使用
close\u fds=True
,stdin、stdout和stderr将无法工作(尽管措辞有点含糊不清,如果你真的使用它们会发生什么)。在简单地添加了
close_fds
之后,您的代码片段对我来说效果很好,但是在Windows平台上省略stdin/stdout/stderr可能会更安全。请注意,从Python 3.7开始,在Windows上不再需要设置
close_fds=True
——这是现在的默认设置,并且与重定向
stdi一起工作n
/
stdout
/
stderr
中的详细信息:请注意,从Python 3.7开始,在Windows上不再需要设置
close\u fds=True
-这是默认设置,与重定向
stdin
/
stdout
/
stderr
一起工作。错误跟踪程序中的详细信息如下:
#!/usr/bin/env python
import os
import sys
import platform
from subprocess import Popen, PIPE

# set system/version dependent "start_new_session" analogs
kwargs = {}
if platform.system() == 'Windows':
    # from msdn [1]
    CREATE_NEW_PROCESS_GROUP = 0x00000200  # note: could get it from subprocess
    DETACHED_PROCESS = 0x00000008          # 0x8 | 0x200 == 0x208
    kwargs.update(creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)  
elif sys.version_info < (3, 2):  # assume posix
    kwargs.update(preexec_fn=os.setsid)
else:  # Python 3.2+ and Unix
    kwargs.update(start_new_session=True)

p = Popen(["C"], stdin=PIPE, stdout=PIPE, stderr=PIPE, **kwargs)
assert not p.poll()
#!/usr/bin/env python
import os
import sys
import platform
from subprocess import Popen, PIPE

# set system/version dependent "start_new_session" analogs
kwargs = {}
if platform.system() == 'Windows':
    # from msdn [1]
    CREATE_NEW_PROCESS_GROUP = 0x00000200  # note: could get it from subprocess
    DETACHED_PROCESS = 0x00000008          # 0x8 | 0x200 == 0x208
    kwargs.update(creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, close_fds=True)  
elif sys.version_info < (3, 2):  # assume posix
    kwargs.update(preexec_fn=os.setsid)
else:  # Python 3.2+ and Unix
    kwargs.update(start_new_session=True)

p = Popen(["C"], stdin=PIPE, stdout=PIPE, stderr=PIPE, **kwargs)
assert not p.poll()