究竟什么是Python多处理模块的.join()方法呢?

Mik*_*iLL 91 python multiprocessing

了解Python 多处理(来自PMOTW文章),并希望对该join()方法的具体用途有所了解.

2008年的一个旧教程中,它声明如果没有p.join()下面代码中的调用,"子进程将处于空闲状态而不会终止,成为僵尸,你必须手动杀死".

from multiprocessing import Process

def say_hello(name='world'):
    print "Hello, %s" % name

p = Process(target=say_hello)
p.start()
p.join()
Run Code Online (Sandbox Code Playgroud)

我添加了一个打印输出PID以及一个time.sleep测试,据我所知,该过程自行终止:

from multiprocessing import Process
import sys
import time

def say_hello(name='world'):
    print "Hello, %s" % name
    print 'Starting:', p.name, p.pid
    sys.stdout.flush()
    print 'Exiting :', p.name, p.pid
    sys.stdout.flush()
    time.sleep(20)

p = Process(target=say_hello)
p.start()
# no p.join()
Run Code Online (Sandbox Code Playgroud)

在20秒内:

936 ttys000    0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000    0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001    0:00.13 -bash
Run Code Online (Sandbox Code Playgroud)

20秒后:

947 ttys001    0:00.13 -bash
Run Code Online (Sandbox Code Playgroud)

行为与p.join()文件末尾添加的行为相同.本周的Python模块提供了一个非常易读的模块说明 ; "要等到一个进程完成其工作并退出,请使用join()方法."但似乎至少OS X正在这样做.

我也想知道这个方法的名称.这个.join()方法在这里连接什么?它是否将一个过程与它结束?或者它只是与Python的本机.join()方法共享一个名称?

dan*_*ano 101

join()方法与threadingor一起使用时与之multiprocessing无关str.join()- 它实际上并不是将任何东西连接在一起.相反,它只是意味着"等待[线程/进程]完成".使用该名称join是因为multiprocessing模块的API看起来与threading模块的API 类似,并且threading模块join用于其Thread对象.使用该术语join来表示"等待线程完成"在许多编程语言中很常见,因此Python也采用了它.

现在,你看到有和没有调用的20秒延迟的原因join()是因为默认情况下,当主进程准备退出时,它将隐式调用join()所有正在运行的multiprocessing.Process实例.这在multiprocessing文档中没有明确说明,但在编程指南部分提到:

还要记住,非守护进程将自动加入.

您可以通过设置覆盖此行为daemon上的标志ProcessTrue之前,要启动的过程:

p = Process(target=say_hello)
p.daemon = True
p.start()
# Both parent and child will exit here, since the main process has completed.
Run Code Online (Sandbox Code Playgroud)

如果这样做,子进程将在主进程完成后立即终止:

守护进程

进程的守护进程标志,一个布尔值.必须在调用start()之前设置它.

初始值继承自创建过程.

当进程退出时,它会尝试终止其所有守护进程子进程.

  • @MikeiLL基本上只要父进程正在运行,你想在后台进行任何操作,但在退出主程序之前不需要优雅地清理它.也许是一个工作进程从套接字或硬件设备读取数据,并通过队列将数据反馈给父进程或为了某种目的在后台处理它?一般来说,我会说使用`daemonic`子进程不是很安全,因为进程将被终止而不允许清理它可能拥有的任何开放资源.(续). (7认同)
  • 我理解`p.daemon = True`是为了"启动一个后台进程,运行时不会阻止主程序退出".但是如果"守护进程在主程序退出之前自动终止",它的用途究竟是什么? (5认同)
  • @MikeiLL更好的做法是在退出主要过程之前通知孩子清理和退出.您可能认为在父进程退出时让守护进程子进程运行是有意义的,但请记住,`multiprocessing` API旨在尽可能地模仿`threading` API.一旦主线程退出,守护进程`threading.Thread`对象就会终止,因此守护进程`multiprocesing.Process`对象的行为方式相同. (5认同)

Rus*_*ove 31

没有join(),主进程可以在子进程之前完成.我不确定在什么情况下会导致僵尸.

主要目的join()是确保在主要过程完成取决于子过程工作的任何事情之前完成子过程.

它的词源join()是它的反面fork,这是用于创建子进程的Unix系列操作系统中的常用术语.一个过程"分叉"成几个,然后"连接"成一个.

  • 它使用名称`join()`因为`join()`是用来等待`threading.Thread`对象完成的东西,而`multiprocessing` API旨在尽可能地模仿`threading` API. . (2认同)

Fre*_*Foo 11

我不打算详细解释它是join做什么的,但这里是它的词源和直觉,它可以帮助你更容易地记住它的含义.

这个想法是执行" 分叉 "成多个过程,其中一个是主人,其余是工人(或"奴隶").当工人完成后,他们"加入"主人,以便可以恢复连续执行.

join方法使主进程等待工作者加入它.该方法可能更好地被称为"等待",因为这是它在主服务器中引起的实际行为(这就是它在POSIX中调用的内容,尽管POSIX线程也将其称为"join").加入只发生在线程正确协作的效果上,这不是主人所做的事情.

自1963年以来,名称"fork"和"join"已在多处理中用于此含义.


Yi *_*ong 5

join()调用可确保在所有多处理过程完成之前不会调用后续代码行。

例如,如果没有join(),下面的代码restart_program()甚至会在进程完成之前调用,这类似于异步,不是我们想要的(您可以尝试):

num_processes = 5

for i in range(num_processes):
    p = multiprocessing.Process(target=calculate_stuff, args=(i,))
    p.start()
    processes.append(p)
for p in processes:
    p.join() # call to ensure subsequent line (e.g. restart_program) 
             # is not called until all processes finish

restart_program()
Run Code Online (Sandbox Code Playgroud)