join 在概念上相当简单 - x.join 表示“在 x 终止之前,当前的执行线程(即进程)无法继续超过 this 点。”
因此,一般来说,您不希望您的 main 线程在某个时间点之后继续进行,直到您的所有工作人员都完成了他们的工作。由于您在主线程中执行task0,因此执行join 会阻止您的主线程继续执行该点,直到您的所有工作人员(task1 和 task2)都完成。
但是等等,我没有在task1 中join!
没错。但是task1 的进程在其所有task2 完成之前仍然不会终止。这与process groups 的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 的输出,没有joins,唯一的修改是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) 的所有成员。
总结一下,伙计
所有这些都是一种冗长的说法:主线程中的join 通常是你所需要的,因为你可以保证任何子进程都会等待他们的子进程在自己终止之前终止。