Python多处理:如果进程';孩子们有孙子吗?
下面是我正在处理的一个玩具问题:Python多处理:如果进程';孩子们有孙子吗?,python,python-2.7,multiprocessing,Python,Python 2.7,Multiprocessing,下面是我正在处理的一个玩具问题: import multiprocessing as mp def task2(): print "I am doing something important." def task1(): listOfProcesses = [] for i in range(5): process = mp.Process(target=task2) process.start() listOfPro
import multiprocessing as mp
def task2():
print "I am doing something important."
def task1():
listOfProcesses = []
for i in range(5):
process = mp.Process(target=task2)
process.start()
listOfProcesses.append(process)
def task0():
listOfProcesses = []
for i in range(5):
process = mp.Process(target=task1)
process.start()
listOfProcesses.append(process)
if __name__ == '__main__':
task0()
现在,我很难理解在这种情况下应该在何处调用join
如果我这样更改task0的定义:
def task0():
listOfProcesses = []
for i in range(5):
process = mp.Process(target=task2)
process.start()
listOfProcesses.append(process)
for process in listOfProcesses:
process.join()
一切似乎都正常,但我不明白我到底在这里做什么<代码>任务1只启动其子级,而不加入它们。那么,加入task0
对task1
意味着什么呢?在类Unix系统(Linux、BSD等)上,mp.Process
实际上调用os.fork
,而生成的进程对象的join
方法调用wait
(或一个变体)1等待它(即,等待特定进程,而不仅仅是任意进程)
fork
的子级只能由其父级等待,2因此task0
可以等待每个task1
,但不能等待任何task1
的task2
任务。同时,每个task1
可以等待自己的task2
任务,但不能等待任何其他task1
任务
由于每个task2
都非常短(并且每个进程在从其target=
函数返回时退出),因此无论您是否显式地加入join
,都很难在这里看到任何差异。您需要做一些更慢的事情(例如,time.sleep()
或做一些实际工作)才能看到任何真正的差异
1实际调用是
os.waitpid()
;请参阅multiprocessing/forking.py
。实际调用在poll
函数中
2如果父进程在不等待其子进程的情况下退出,则这些子进程将被“孤立”并作为代理父进程传递给PID 1(init)。进程1循环调用wait
(或等效程序)以清除它们
(Windows变体使用不同的调用,例如,它不能
fork
,而我不在Windows上工作,因此我不确定那里的实际情况。)join
在概念上相当简单-x.join
表示“当前线程(即进程)在x
终止之前,无法继续执行此点。”
因此,一般来说,在所有工作人员完成工作之前,您不希望您的main线程通过某个点。由于您在主线程中执行task0
,因此执行join
会阻止主线程通过该点,直到所有工作人员完成为止(任务1和任务2都已完成
但是等等,我没有加入到任务1中!
没错。但是task1
的进程在其所有task2
完成之前不会终止。这与POSIX的概念有关-父进程在其所有子进程终止之前不会终止。因此,让我们看看这个简化示例的输出:
import multiprocessing as mp
from time import sleep
def task2():
sleep(1)
print "I am doing something important."
def task1():
for i in range(2):
process = mp.Process(target=task2)
process.start()
print 'task1 done'
def task0():
process = mp.Process(target=task1)
process.start()
process.join()
if __name__ == '__main__':
task0()
print 'all done'
输出:
task1 done
I am doing something important.
I am doing something important.
all done
正如您所看到的,task1
已经结束,但直到其子进程结束后才终止,这意味着task0
中的join
块正确地阻止了主线程终止,直到所有工作进程都终止
为了好玩,这里是运行原始脚本时的ps jf
输出,没有join
s,唯一的修改是time。sleep
被扔进task2
中,这样我就可以捕捉到它在运行:
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
6780 7385 7385 7385 pts/11 7677 Ss 1000 0:00 bash
7385 7677 7677 7385 pts/11 7677 R+ 1000 0:00 \_ ps jf
6780 6866 6866 6866 pts/7 7646 Ss 1000 0:00 bash
6866 7646 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7646 7647 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7647 7672 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7647 7673 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7647 7674 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7647 7675 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7647 7676 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7646 7648 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7648 7665 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7648 7666 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7648 7667 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7648 7668 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7648 7669 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7646 7649 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7649 7656 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7649 7657 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7649 7658 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7649 7659 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7649 7660 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7646 7650 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7650 7652 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7650 7653 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7650 7654 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7650 7655 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7650 7670 7646 6866 pts/7 7646 S+ 1000 0:00 | \_ python test
7646 7651 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7651 7661 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7651 7662 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7651 7663 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7651 7664 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
7651 7671 7646 6866 pts/7 7646 S+ 1000 0:00 \_ python test
您可以看到,我们的主进程(执行task0
)和“第一个子进程”(执行task1
)仍然存在,尽管它们显然没有python代码可执行。它们也是同一进程组的所有成员(TPGID
)
总结一下,伙计
所有这一切都是一种冗长的说法:
在主线程中加入
通常是您所需要的,因为您可以保证任何子进程都将在其子进程终止之前等待其子进程终止。@roippi我输入了一个错误,我已经对其进行了修复,并添加了一点内容,以使我调用的task0
变得清晰。