以下是我正在处理的一个玩具问题:
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
的定义:
一切看起来都很正常,但我不明白我到底在这里做什么。task1
只开始它的子级,它不连接它们。那么加入task0
对task1
意味着什么呢?在
join
在概念上相当简单-x.join
表示“当前执行线程(即进程)在x
终止之前,不能越过这个点。”因此,一般情况下,您不希望main线程继续超过某个点,直到您的所有工作人员都完成了他们的工作。由于您在主线程中执行
task0
,因此执行join
会阻止主线程继续超过该点,直到您的所有工作线程(包括task1
和task2
)都完成。在但是等等,我没有
join
在task1
里!在没错。但是
task1
的进程在其所有的task2
完成之前仍然不会终止。这与process groups的POSIX概念有关,父进程在其所有子进程终止之前不会终止。那么,让我们看看这个简化示例的输出:输出:
^{pr2}$如您所见,
task1
到达了它的结尾,但直到它的子进程结束才终止——这意味着我们在task0
中的join
块正确地阻止了我们的主线程在所有worker都终止之前终止。在有趣的是,当运行没有}中,这样我就可以捕捉到它的运行:
join
的原始脚本时,ps jf
的输出是join
,只有的修改是time.sleep
被扔到{您可以看到,我们的主进程(执行
task0
)和“第一个子进程”(完成task1
的那些)仍然活着,尽管它们显然没有足够的python代码来执行。它们也是同一进程组(TPGID
)的所有成员。在总结一下,伙计
所有这些都是一种冗长的说法:主线程中的
join
通常是您所需要的,因为您可以保证任何子进程在其自身终止之前都会等待它们的子进程终止。在在类Unix的系统(Linux、BSD等)上,
mp.Process
实际上调用os.fork
,而结果process对象的join
方法调用wait
(或变量)1等待它(即等待特定于的进程,而不仅仅是任意进程)。在一个{{}的儿童只能由其父母代为{}-代之,2所以{}可以等待每一个{>},而不是任何一个{{}}{{>}{{}}。同时,同时,每一个{{}可以等待自己所有的{{}}s,而不是其他任何其他{{}{{{}}{{}}{{}{{{}}{{}}}}}}}{{{
因为每个
task2
都很短(并且每个进程在从其target=
函数返回时都会退出),因此无论是否显式地join
都很难看出任何区别。你需要做一些慢一点的事情(例如,time.sleep()
或者做一些真正的工作)来发现真正的区别。在1实际调用是
os.waitpid()
;请参见multiprocessing/forking.py
。实际调用在poll
函数中。在2如果父进程没有等待其子进程而退出,则这些子进程将“孤立”并作为代理父进程传递给PID 1(init)。进程1循环调用
wait
(或等效函数)来清理它们。在(例如,Windows变体使用了不同的调用它不能
fork
,而且我不在Windows上工作,所以我不确定在那里情况如何。)相关问题 更多 >
编程相关推荐