1.1、multiprocessing模块
multiprocessing是Python的标准模块,主要用来编写多进程,通过该模块的Process进程类型,可以方便的创建和管理多个进程,可以使用该模块提供的Lock|RLock进程锁类型、Event事件类型、Condition条件类型等等完成进程间的同步操作。
和多线程操作方式类似,多进程的实现方式也提供了面向过程的实现和面向对象的实现。
1.2、multiprocessing常见属性和方法
名称 | 描述 |
---|---|
Process | 进程类型,用于创建和管理进程 |
Lock | RLock |
Event | 进程事件类型 |
Condition | 进程条件类型,用于进程同步 |
Queue | 进程队列类型,用于对进程数据共享 |
Manager | 进程管理类型,用于多进程数据共享 |
Listener\Client | 进程监听\客户端,基于网络进程之间的数据共享 |
2.1、多进程的基础操作
(1)面向过程编程
import multiprocessing,os
#函数式进程
def pro():
print("我是一个独立进程",os.getpid(),os.getppid())
#os.getpid()查看当前进程编号
#os.getppid()查看当前进程的父进程的编号
if __name__ == '__main__':
print("mian进程:", os.getpid(), "pycharm:", os.getppid())
jincheng1 = multiprocessing.Process(target=pro)
jincheng2 = multiprocessing.Process(target=pro)
jincheng1.start()
jincheng2.start()
(2)面向对象编程
import multiprocessing,os
#对象式进程
class Myprocess(multiprocessing.Process):
def __init__(self,name):
super().__init__(name = name)
自定义进程类时,需重写run方法
def run(self):
print("我是对象式单独进程:",self.name,"进程号:",os.getpid(),"父进程号:",os.getppid())
if __name__ == '__main__':
#创建进程对象
pro1 = Myprocess("进程1")
pro2 = Myprocess("进程2")
#启动进程
pro1.start()
pro2.start()
运行结果:
3.1、带参数的进程 数据是否共享、独立?
问题一、全局变量、可以被多个进程访问吗?
from multiprocessing import current_process,Process,Pool
import time
#全局变量:
ticket = 3
def my_proc():
time.sleep(0.1)
# 1.多个进程,能不能都读取到全局变量的值?True
for i in range(ticket):
print(current_process().name,":",i)
if __name__ == '__main__':
#创建进程池,进程池有两个进程
pool = Pool(2)
#异步获取任务
for i in range(2):
pool.apply_async(my_proc)
# 停止获取任务,并提交任务
pool.close()
# 独占进程,该进程运行完,其他进程才能运行
pool.join()
print(ticket)
运行结果:
结论:
(1)两个进程都能访问全局变量;
(2)同时也能看出,两个进程访问的全局变量都是独立的,即两个进程都复制了一份程序,单独运行
问题二、#问题:怎么解决进程之间的数据通信|共享
import multiprocessing,time
#解决方案1:通过第三方进行交互
#A进程将数据存储到文件、数据库中
#B进程从文件、数据库中读取数据
#文件、数据库是独立于A和B进程之外的第三方,能够被A和B同时访问
#解决方案2:通过通过第三方、独立于进程之外的数据类型完成进程之间的通信
#python 提供了如下几种方案
#1、事件对象multiprocessing.Event-进程之间的状态标记通信
'''
threading.Event
multiprocess.Event
'''
event = multiprocessing.Event()#创建进程事件对象
def xiao_fan(event):
print("生产。。。")
print("售卖。。。")
time.sleep(1)
event.set()#进程标记、告诉其他进程可以运行
event.clear()#清除标记
print("等待进餐")
event.wait()#进程等待
print("谢谢光临")
def gu_ke(event):
event.wait()
print("准备买早餐")
print("买早餐")
print("吃早餐")
time.sleep(1)
print("很好吃")
event.set()
event.clear()
if __name__ == '__main__':
proc1 = multiprocessing.Process(target=xiao_fan,args=(event,))
proc2 = multiprocessing.Process(target=gu_ke,args=(event,))
proc1.start()
proc2.start()
#运行结果
# 生产。。。
# 售卖。。。
# 等待进餐
# 准备买早餐
# 买早餐
# 吃早餐
# 很好吃
#可以看出运行过程,通过事件对象,达到进程同步
3.2、多进程的简化、内置进程池
多进程的操作在实际应用中也是非常多的,但是纯底层的代码开发控制并发也是一件非常繁
琐的事情,所以就出现了面向过程多进程并发的优化操作方式:进程池 Pool
(1)Pool对象的属性和方法
名称 | 描述 |
---|---|
apply(func,args) | 同步运行,传递参数args并执行函数func,同时阻塞当前当前进程知道该函数执行完成,函数func只会在京城之中的一个进程中运行 |
apply_async(func,args,callback,error_callback) | 传递参数 args 并执行函数 func,该方法不会形成阻塞函数执行完成之后可以通过结果对象的 get()方法获取结果如果结果对象可用时会自动调用 callback 指定的函数如果结果对象调用失败时会自动调用 error_callback 指定的函数 |
close() | Pool 进程池的底层工作机制是向进程池提交任务产生工作进程执行该方法是主动停止给进程池提交任务,并等待所有提交任务执行完成退出 |
terminate() | 立即结束该进程,当进程池对象被回收时自动调用该方法 |
join() | 等待工作进程退出,再次之间必须调用 close()或者 teminate |
(2)进程池的基本实现
'''
进程池:包含多个进程的池子,包含并且管理多个进程的对象
__init__(num)初始化函数,用于创建一个进程池
apply(func,args)同步执行一个函数,当进程中的函数执行完才能推出
apply_async(func,args)异步非阻塞执行一个函数
close()停止向进程池提交任务
jion()独占
'''
import multiprocessing,time,os
def my_pro():
print(multiprocessing.current_process().name,"一个进程正在工作",os.getpid(),os.getppid())
time.sleep(1)
if __name__ == '__main__':
#创建一个进程池
pool = multiprocessing.Pool(4)
#循环任务
for i in range(80):
pool.apply_async(my_pro)
#停止提交
pool.close()
#独占内存
pool.join()
可以看到进程池创建四个工作进程处理8个任务
**重点:**close()提交任务