python多进程不同实现方法的异同点

Posted by BHH on February 29, 2016

最近一直在用python编写大数据分析程序,其中用到了多进程的技术,python实现多进程有多种方法,不同方法的运行效果不尽相同,通过这两天的测试整理,虽然不一定很全面,但有些内容python官方文档也没有涉及,因此赶紧写下来方便以后使用,同时也供大家参考,不正确的地方也请指出。

        Python实现多进程主要有以下三种方法:
        1. 使用multiprocessing.Process()
        2. 使用os.fork() (仅Unix)
        3. 使用subprocess.Popen()

1. multiprocessing.Process() 创建的子进程

1)如果子进程的daemon=False或默认,如果有子进程未结束,即使主进程的所有逻辑已完成,也必须等  到子进程结束后才能退出。
2)如果子进程的daemon=True,一旦主进程的所有逻辑已经完成,主进程会立即终止仍在运行的子进程,并退出。
3)无论子进程daemon=True or False
向主进程发送SIGTERM 或 SIGKILL 信号, 主进程停止,子进程不受影响继续运行。
向子进程发送SIGTERM 或 SIGKILL 信号, 子进程停止,主进程不受影响继续运行。
4)关于Zombie僵尸进程
如果子进程自行结束或被其他进程(包括主进程)kill或terminate,而主进程仍然在运行,并且主进程中未调用过os.wait()os.waitpid()或子进程的join()方法,该子进程将进入僵尸状态(通过 ps命令,状态显示为Z)直到主进程结束。
     CAUTION:
如果子进程daemon=True, 主进程中调用os.wait() or os.waitpid() 会在退出时产生OSError exception ([Errno 3] No such process),但调用join()方法没问题,不清楚为什么。

2. os.fork() 创建的子进程

1)如果主进程的所有逻辑已完成,不需要等待子进程结束就能退出。
2)主进程退出后,不影响子进程的运行状态。
3)如果子进程代码块后面还有代码,这部分代码会被执行2次,一次是主进程执行的,一次是子进程结束后执行的。比如,下面的“parent”会被输出2次。

  pid=os.fork()
  if pid==0:
    print("forked child")
  print("parent")

为避免这种情况,可以这样写:

  pid=os.fork()
  if pid==0:
    print("forked child")
  else:
    print("parent")

以上几点与Process()不同。

下面2点与Process()相同:
4)向主进程发送SIGTERM 或 SIGKILL 信号, 主进程停止,子进程不受影响继续运行。向子进程发送SIGTERM 或 SIGKILL 信号, 子进程停止,主进程不受影响继续运行。
5)关于Zombie僵尸进程
如果子进程自行结束或被其他进程(包括主进程)kill或terminate,而主进程仍然在运行,并且主进程中未调用过os.wait()或os.waitpid()方法,该子进程将进入僵尸状态(通过 ps命令,状态显示为Z)直到主进程结束。

3. subprocess.Popen() 创建的子进程

1)如果主进程的所有逻辑已完成,不需要等待子进程结束就能退出。
2)主进程退出后,不影响子进程的运行状态。
以上几点与Process()不同。

下面2点与Process()相同:
3)向主进程发送SIGTERM 或 SIGKILL 信号, 主进程停止,子进程不受影响继续运行。向子进程发送SIGTERM 或 SIGKILL 信号, 子进程停止,主进程不受影响继续运行。
4)关于Zombie僵尸进程
如果子进程自行结束或被其他进程(包括主进程)kill或terminate,而主进程仍然在运行,并且主进程中未调用过os.wait()或subprocess.wait()或subprocess.communicate(),该子进程将进入僵尸状态(通过 ps命令,状态显示为Z)直到主进程结束。

 

最后说一下os._exit()和sys.exit()两个方法产生的不同结果:

  A进程调用os._exit()方法后产生的效果等同于向A进程发送SIGTERM或SIGKILL信号。
  A进程调用sys.exit()方法后产生的效果等同于A进程代码执行完毕,自行结束。

  因此,针对上面的第1类子进程,如果主进程调用了os._exit()方法,主进程立即退出,且不影响子进程的运行。如果调用了sys.exit(),主进程停止运行,如果子进程daemon=False,需等待子进程结束后才能退出;如果子进程daemon=True,则终止子进程并退出。