&引用;火与遗忘”;来自Python脚本的进程

&引用;火与遗忘”;来自Python脚本的进程,python,subprocess,Python,Subprocess,如何从Python脚本启动一个进程(例如,另一个Python脚本),使“子”进程与“父”进程完全分离,这样父进程就可以a)在不等待子进程完成的情况下继续愉快地运行,b)在不终止子进程的情况下终止进程 家长: import os print "Parent started" os.system("./child.py") print "Parent finished" import time print "Child started" time.sleep(10) print "Child

如何从Python脚本启动一个进程(例如,另一个Python脚本),使“子”进程与“父”进程完全分离,这样父进程就可以a)在不等待子进程完成的情况下继续愉快地运行,b)在不终止子进程的情况下终止进程

家长:

import os

print "Parent started"
os.system("./child.py")
print "Parent finished"
import time

print "Child started"
time.sleep(10)
print "Child finished"
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
Traceback (most recent call last):
  File "./child.py", line 5, in <module>
  File "./parent.py", line 13, in <module>
        time.sleep(10)
time.sleep(5)
KeyboardInterrupt
KeyboardInterrupt
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
  File "./parent.py", line 12, in <module>
    time.sleep(5)
KeyboardInterrupt

$ Child finished
子项:

import os

print "Parent started"
os.system("./child.py")
print "Parent finished"
import time

print "Child started"
time.sleep(10)
print "Child finished"
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
Traceback (most recent call last):
  File "./child.py", line 5, in <module>
  File "./parent.py", line 13, in <module>
        time.sleep(10)
time.sleep(5)
KeyboardInterrupt
KeyboardInterrupt
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
  File "./parent.py", line 12, in <module>
    time.sleep(5)
KeyboardInterrupt

$ Child finished
运行
parent.py
打印:

Parent started
Child started
Child finished
Parent finished
我希望它打印的内容:

Parent started
Child started
Parent finished
(seconds later)
Child finished

既然您提到了
os.system
,我认为值得一提的是,您应该使用
os.spawn*
和模式
p_NOWAIT
来实现“忘记”部分

但是
子流程
模块提供了对
操作系统
操作系统、spawn*
等的替换,所以您应该像这样使用它

import subprocess
p = subprocess.Popen("./child.py")
print "pid = ", p.pid

正如我在注释中所解释的,两个进程
parent.py
child.py
仍在同一进程组中,因此终端将向前台进程组中的所有进程转发信号(如
Ctrl-C
),因此当您
Ctrl-C
时,这两个进程都将被杀死。因此,如果您不想这样做,您可以强制
child.py
位于具有以下内容的新流程组中:

#!/usr/bin/env python
import subprocess
import time
import os
p = subprocess.Popen("./child.py", preexec_fn=os.setsid)
print "pid = ", p.pid
time.sleep(30) # Ctrl-C at this point will not kill child.py
print "parent exit"

回答我自己的问题:正如@kevinsa所建议的那样,我在命令末尾使用了
os.system
&
。这允许在不终止子进程的情况下终止父进程

下面是一些代码:

child.py

#!/usr/bin/python

import time
print "Child started"
time.sleep(10)
print "Child finished"
parent.py,使用subprocess.Popen:

#!/usr/bin/python

import subprocess
import time

print "Parent started"
subprocess.Popen("./child.py")
print "(child started, sleeping)"

time.sleep(5)

print "Parent finished"
输出:

import os

print "Parent started"
os.system("./child.py")
print "Parent finished"
import time

print "Child started"
time.sleep(10)
print "Child finished"
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
Traceback (most recent call last):
  File "./child.py", line 5, in <module>
  File "./parent.py", line 13, in <module>
        time.sleep(10)
time.sleep(5)
KeyboardInterrupt
KeyboardInterrupt
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
  File "./parent.py", line 12, in <module>
    time.sleep(5)
KeyboardInterrupt

$ Child finished
输出:

import os

print "Parent started"
os.system("./child.py")
print "Parent finished"
import time

print "Child started"
time.sleep(10)
print "Child finished"
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
Traceback (most recent call last):
  File "./child.py", line 5, in <module>
  File "./parent.py", line 13, in <module>
        time.sleep(10)
time.sleep(5)
KeyboardInterrupt
KeyboardInterrupt
$ ./parent.py
Parent started
(child started, sleeping)
Child started
^CTraceback (most recent call last):
  File "./parent.py", line 12, in <module>
    time.sleep(5)
KeyboardInterrupt

$ Child finished
$./parent.py
父母开始
(孩子开始睡觉)
孩子开始
^CTraceback(最近一次通话最后一次):
文件“/parent.py”,第12行,在
时间。睡眠(5)
键盘中断
$Child已完成

注意孩子如何生活在Ctrl-C之外。

使用
asyncio
您可以编写一个简单的装饰程序作为
@background

import asyncio
import time

def background(f):
    def wrapped(*args, **kwargs):
        return asyncio.get_event_loop().run_in_executor(None, f, *args, *kwargs)

    return wrapped

@background
def foo():
    time.sleep(1)
    print("foo() completed")

print("Hello")
foo()
print("I didn't wait for foo()")
产生

>>> Hello
>>> I didn't wait for foo()
>>> foo() completed

看看
subprocess
模块,特别是
subprocess.Popen(…).pid
@sberry:Nice,看起来就像只使用
subprocess.Popen(“./child.py”)
做的正是我需要的,尽管文档中根本不清楚。如果您添加您的评论作为答案,我很乐意接受,谢谢。根据平台的不同,您可能会在shell命令末尾添加一个
&
,它也会起作用。@kevinsa5:yep,效果更好-我刚刚发现,使用Popen(),如果父进程被杀死,子进程似乎也会被杀死。嘿,谢谢你回答这个老问题。但是
subprocess.Popen
有一个问题:如果父进程被终止,那么子进程也会被终止。你是什么意思?我试过这段代码,但至少在父母因自然原因死亡的情况下,孩子并没有被终止。Ctrl-C(所有信号)是不同的。终端接收信号并将其转发到前台进程组中的任何进程。此处的进程组包括parent.py和child.py,因此两者都会被杀死。我将尝试提供特定的Popen序列,以便在新进程组中创建子进程。