python多进程——multiprocessing.Process

  简介                               

  multiprocessing是一个使用类似于threading模块的API支持生成进程的包。该multiprocessing软件包提供本地和远程并发。因此,该multiprocessing模块允许程序员充分利用给定机器上的多个处理器。可以在Unix和Windows上运行。

multipleprocessing文档

Process(group=Nonetarget=Nonename=Noneargs=()kwargs={}*daemon=None)

应该始终使用关键字参数调用构造函数

  • group参数永远为None,该参数仅用于兼容threading.Thread
  • target应该是一个可以调用的对象,它会被run()方法调用
  • name是进程名
  • args是target所调用方法的参数
  • kwargs是target所调用方法的关键字参数
  • daemon默认为None,意味着从创建进程中继承,可设为True(守护进程)或False(非守护进程)

start()

  • 启动进程,只能调用一次,他会在进程中调用run方法

join([timeout])

  • 设主进程为m,子进程为s,m中调用s.join():阻塞m,直到s进程结束,timeout是一个正数,它最多会阻塞timeout秒 ,另外,s.join()可调用若干次
  • 一个进程p调用自己进程的join (p.join()) 可能会导致死锁【自己join自己这种骚操作不会,因此没实验】
  • 只能在调用s.start()后调用s.join()

  join可防止产生僵尸进程,文档中的编程指南中指出: 每次开启一个新进程,所有未被join的进程会被join(也就是说非守护进程会自动被join),但即便如此也要明确地join启动的所有进程。 因此如果不手动地join子线程,主进程也会等待子进程中止之后再中止

【另外join会影响守护进程的行为,后面探讨】

(一)Process开启进程:                       

# -*- coding:utf-8 -*-
import os
from multiprocessing import Process

def func(name):
    print(‘%s进程%d,父进程%d‘ % (name, os.getpid(), os.getppid()))

‘‘‘
在Windows中,Process开启进程会再次导入此文件,为防止导入时再次执行,需要添加
if __name__ == ‘__main__‘:
‘‘‘
if __name__ == ‘__main__‘:
    func(‘主‘)
    p = Process(target=func, args=[‘子‘])
    p.start()
    p.join()

 结果:

主进程16452,父进程21852
子进程28472,父进程16452

(二)自定义类继承Process,重写run方法               

  如果子类重写构造函数,则必须确保它在对进程执行任何其他操作之前调用构造函数 [Process.__init__() ]。

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

class InheritTest(Process):

    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(‘我是子进程%s,进程id=%d,父进程id=%d‘ % (self.name, os.getpid(), os.getppid()))
        time.sleep(2)

if __name__ == ‘__main__‘:
    print(‘我是主进程, 进程id=%d,父进程id=%d‘ % (os.getpid(), os.getppid()))
    p = InheritTest(‘小明‘)
    p.start()
    p.join()

结果:

我是主进程, 进程id=18408,父进程id=21852
我是子进程小明,进程id=22640,父进程id=18408

  若多个进程被join,阻塞时长是他们(包括主进程在这期间的执行时间)中执行时间最长的

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time

def short_time():
    print(‘进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))
    time.sleep(2)

def long_time():
    print(‘进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))
    time.sleep(4)

if __name__ == "__main__":
    p1 = Process(target=long_time)
    p2 = Process(target=short_time)
    p3 = Process(target=short_time)
    p4 = Process(target=short_time)

    p1.start()
    p2.start()
    p3.start()
    p4.start()

    print(‘1号进程阻塞中‘)
    p1.join()
    print(‘2号进程阻塞中‘)
    p2.join()
    print(‘3号进程阻塞中‘)
    p3.join()
    print(‘4号进程阻塞中‘)
    p4.join()

‘‘‘
p1-p4异步执行,p1执行时间最长,那么p1.join()阻塞完后,其它进程已经执行完了,
p2-p4.join()不阻塞,直接执行
‘‘‘

结果:

1号进程阻塞中
进程pid=26404,ppid=17928
进程pid=17960,ppid=17928
进程pid=15592,ppid=17928
进程pid=8724,ppid=17928
2号进程阻塞中
3号进程阻塞中
4号进程阻塞中

  问1:只能在父进程中join子进程吗?

  问1的解释: 在子进程中join其它同级的子进程会抛出异常 AssertionError: can only join a child process,因此只能在父进程中join子进程:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

def func1():
    time.sleep(2)
    print(‘func1 进程pid={} ppid={}‘.format(os.getpid(), os.getppid()))

def func2(p1):
    p1.join()
    print(‘func2 进程pid={} ppid={}‘.format(os.getpid(), os.getppid()))

if __name__ == "__main__":
    print(‘主进程id {}‘.format(os.getpid()))
    p1 = Process(target=func1)
    p2 = Process(target=func2, args=[p1])

    p2.start()  # 和下面代码互换会报另一个异常
    p1.start()
主进程id 14796
Process Process-2:
Traceback (most recent call last):
...............
AssertionError: can only join a child process
func1 进程pid=30100 ppid=14796

  

run()

  • 表示进程活动的方法。调用target指定的函数,如果有参数,会按顺序传入
  • 自定义进程类要在子类中覆盖此方法。

【单独调用run不会开启子进程】

is_alive()

  • 查看进程是否还活着。
  • 粗略地说,从start() 方法返回到子进程终止的那一刻,进程对象处于活动状态。

pid

  • 返回进程ID。在产生该过程之前,这将是 None

exitcode

  • 子进程的退出码,如果进程尚未中止,返回None,如果是-N,表示被信号N中止
# -*- coding:utf-8 -*-
import os
from multiprocessing import Process
import time

def func(name):
    print(‘%s进程%d,父进程%d‘ % (name, os.getpid(), os.getppid()))
    if name != ‘主‘:
        time.sleep(2)

if __name__ == ‘__main__‘:
    func(‘主‘)
    p = Process(target=func, args=[‘子‘])
    p.start()
    print(‘p.pid()‘, p.pid)
    print(‘p.is_alive()=‘, p.is_alive())
    print(‘p.exitcode=‘, p.exitcode)
    p.join()
    print(‘p.exitcode=‘, p.exitcode)
    print(‘p.is_alive()=‘, p.is_alive())

结果

主进程1548,父进程21852
p.pid() 24000
p.is_alive()= True
p.exitcode= None
子进程24000,父进程1548
p.exitcode= 0
p.is_alive()= False

daemon

  • 进程的守护进程标志,一个布尔值。必须在start()调用之前设置 它。
  • 初始值继承自创建过程。
  • 当进程退出时(更确切地说是该进程的代码执行完毕后),它会尝试终止其所有守护子进程。
  • 不允许守护进程创建子进程。否则,守护进程会在进程退出时使这些进程变成孤儿进程。此外,这些不是Unix守护程序或服务,它们是正常进程,如果非守护进程已退出,它们将被终止(不会被join)。

(三)开启一个守护进程:                       

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

def daemon_func():
    time.sleep(2)
    print(‘守护进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

if __name__ == "__main__":
    print(‘主进程id {}‘.format(os.getpid()))
    p = Process(target=daemon_func)
    p.daemon = True
    p.start()
    # p.join()
当p.join()注释后,主进程中止,守护进程也中止,因此输出:
主进程id 15096
若取消注释,守护进程被join,主进程会等待此守护进程,输出为:
主进程id 10896
守护进程pid=19404,ppid=10896

(四) 主进程分别开启一个守护进程和非守护进程:            

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

# 守护进程p1执行
def daemon_func():
    time.sleep(1)
    print(‘daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

# 非守护进程p2执行
def non_daemon_func():
    time.sleep(2)
    print(‘non_daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

if __name__ == "__main__":
    print(‘主进程id {}‘.format(os.getpid()))

    p1 = Process(target=daemon_func)
    p1.daemon = True
    p2 = Process(target=non_daemon_func)

    p1.start()
    p2.start()
  主进程执行完立即中止守护进程(主进程此时自己没中止),主进程等待非守护进程,然后中止因此执行结果是:
主进程id 24588
non_daemon_func 进程pid=3772,ppid=24588   ### 这里ppid是24588,而不是1,说明主进程还未中止

(4.1)守护进程被join:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

# 守护进程p1执行
def daemon_func():
    time.sleep(1)
    print(‘daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

# 非守护进程p2执行
def non_daemon_func():
    time.sleep(2)
    print(‘non_daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

if __name__ == "__main__":
    print(‘主进程id {}‘.format(os.getpid()))

    p1 = Process(target=daemon_func)
    p1.daemon = True
    p2 = Process(target=non_daemon_func)

    p1.start()
    p2.start()

    p1.join()  # join守护进程
主进程执行完后没中止守护进程,并等待非守护进程执行完:
主进程id 24416
daemon_func 进程pid=27312,ppid=24416
non_daemon_func 进程pid=12408,ppid=24416
守护进程睡三秒,主进程仍会等待守护进程执行完:
主进程id 20336
non_daemon_func 进程pid=24528,ppid=20336
daemon_func 进程pid=16596,ppid=20336

  守护进程被join后,主进程会等待守护进程执行完。因此,join守护进程,还不如直接开非守护进程

(4.2)非守护进程被join

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

# 守护进程p1执行
def daemon_func():
    time.sleep(1)
    print(‘daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

# 非守护进程p2执行
def non_daemon_func():
    time.sleep(2)
    print(‘non_daemon_func 进程pid={},ppid={}‘.format(os.getpid(), os.getppid()))

if __name__ == "__main__":
    print(‘主进程id {}‘.format(os.getpid()))

    p1 = Process(target=daemon_func)
    p1.daemon = True
    p2 = Process(target=non_daemon_func)

    p1.start()
    p2.start()

    p2.join()  # join非守护进程
非守护进程被join,主进程等待非守护进程,非守护进程中止后,立即中止守护进程。------------------------------------------------------------------------------
注意【1.主进程只join非守护进程】和【2.主进程没有join任何进程】的区别:
1: 主进程会被join阻塞,等到非守护进程中止后,中止守护进程

2: 主进程执行完立即中止守护进程,若非守护进程未中止,等待

其实都是主进程的代码执行完毕后,才中止子守护进程,只是1包含了手动join进程的代码,阻塞后代码才算执行完毕。-----------------------------------------------------------------
守护进程睡1秒后,非守护进程还在睡,主进程被阻塞住,因此守护进程有输出
主进程id 11284
daemon_func 进程pid=5308,ppid=11284
non_daemon_func 进程pid=30364,ppid=11284
守护进程睡3秒后,非守护进程在2秒时睡醒后中止,主进程便在此时中止守护进程,因此守护进程没有输出
主进程id 24912
non_daemon_func 进程pid=19892,ppid=24912

join在很多地方都有用到,预知join的行为并合理利用join,避免产生死锁

terminate()

  中止进程,在Unix上是用SIGTERM信号完成的;在Windows上,使用TerminateProcess();

  注意,退出处理程序和finally子句等不会被执行

  被中止进程的子进程不会被中止

  避免使用此方法:使用该方法停止进程可能导致进程当前使用的任何共享资源被破坏或不可用于其它进程,最好只考虑该方法用在从不使用共享资源的进程上

参考:

官方文档

如有意见或建议,一起交流;如有侵权,请告知删除。

原文地址:https://www.cnblogs.com/Magic-Dev/p/11420692.html

时间: 2024-11-06 16:38:42

python多进程——multiprocessing.Process的相关文章

Python多进程multiprocessing(二)

紧接上文 在上文Python多进程multiprocessing(一)中我们介绍了多进程multiprocessing的部分基础操作,在本文中,我们将继续介绍关于多进程的一些知识,比如进程池Pool这个有用的东东.马上开始吧! 使用实例 实例1 import multiprocessing as mp def job(x): return x*x def multicore(): pool = mp.Pool(processes=2) res = pool.map(job,range(10))

python多进程-----multiprocessing包

multiprocessing并非是python的一个模块,而是python中多进程管理的一个包,在学习的时候可以与threading这个模块作类比,正如我们在上一篇转载的文章中所提,python的多线程并不能做到真正的并行处理,只能完成相对的并发处理,那么我们需要的就是python的多进程来完成并行处理,把所有的cpu资源都利用起来.multiprocessing的很大一部分与threading使用同一套API,只不过换到了多进程的环境.这里面要注意,对于多进程来说,win32平台和unix平

Python多进程multiprocessing使用示例

mutilprocess简介 像线程一样管理进程,这个是mutilprocess的核心,他与threading很是相像,对多核CPU的利用率会比threading好的多. import multiprocessing def worker(num): """thread worker function""" print 'Worker:', num return if __name__ == '__main__': jobs = [] for i

python ---多进程 Multiprocessing

和 threading 的比较 多进程 Multiprocessing 和多线程 threading 类似, 他们都是在 python 中用来并行运算的. 不过既然有了 threading, 为什么 Python 还要出一个 multiprocessing 呢? 原因很简单, 就是用来弥补 threading 的一些劣势, 比如在 threading 教程中提到的GIL. 创建多进程 import multiprocessing as mp import threading as td def

python多进程multiprocessing Pool相关问题

python多进程想必大部分人都用到过,可以充分利用多核CPU让代码效率更高效. 我们看看multiprocessing.pool.Pool.map的官方用法 map(func, iterable[, chunksize]) A parallel equivalent of the map() built-in function (it supports only one iterable argument though). It blocks until the result is ready

python 多进程multiprocessing 模块

multiprocessing 常用方法: cpu_count():统计cpu核数 multiprocessing.cpu_count() active_children() 获取所有子进程 multiprocessing.active_children() preces() 创建一个进程对象 multiprocessing.Preces(target=function_name, args=()) target: 函数名 args: 函数需要的参数,以tuple形式传入,一个参数时需(1,)

python多进程(multiprocessing调用类函数)

#coding=utf-8 import os import multiprocessing from time import ctime, sleep from selenium import webdriver class testClass(object): def worker(self, interval, browser="Chrome", url="http://loginurl"): driver = eval("webdriver.%s(

python多进程multiprocessing模块中Queue的妙用

最近的部门RPA项目中,小爬为了提升爬虫性能,使用了Python中的多进程(multiprocessing)技术,里面需要用到进程锁Lock,用到进程池Pool,同时利用map方法一次构造多个process.Multiprocessing的使用确实能显著提升爬虫速度,不过程序交由用户使用时,缺乏一个好的GUI窗口来显示爬虫进度.之前的文章中使用了Chrome浏览器来渲染js脚本生成了进度条.但是鉴于Chrome在运行时十分吃内存资源,用Chrome只是生成一个进度条难免有些“大材小用”,所以,小

Python多进程multiprocessing

import multiprocessing import time # 具体的处理函数,负责处理单个任务 def func(msg): # for i in range(3): print (msg) time.sleep(1) return "done " + msg if __name__ == "__main__": # 进程池,创建多个进程,并行执行 pool = multiprocessing.Pool(processes=4) # 把运行的结果添加到一