python3.x Day6 多进程
多进程:
1、每个子进程申请到的资源都是独立的,不与其他进程共享。
2、语法上和线程基本上差不多,使用multiprocessing.Process(target=xxxx,args=(xxx,xxx,xxx,))创建子进程。
3、包含的方法,与线程的也差不多
4、配合os.getpid()方法取得当前进程ID,配合os.getppid()方法取得当前进程的父进程ID
多进程之间的通信:
消息传递:
import queue这个队列模块,是线程queue,只能作用于当前进程,子进程已经不在当前进程中了,所以这个模块就不适用了。
可以使用进程Queue来搞定,进程Queue,q=multiprocessing.Queue(),语法上和线程queue(import queue)差不多的。
使用时,一定要传给子进程运行的函数,线程的queue这个问题还好,但线程queue是无法传递给子进程的,
说白了,进程queue就干进程的事,线程queue就干线程的事,完全不能混用,编写代码必须注意
进程queue原理:进程queue不是共享数据,而是每个进程一个queue,克隆的,还有个不在任何进程内的中间件从A进程来序列化这个queue,
再反序列化这个queue给B进程,来完成数据的传递,这里修改的,不是同一份数据。
还可以使用Pipe管道实现,paraent_pp,child_pp=multiprocessing.Pipe(),会返回一个通道的两端,父进程端,子进程端,没有差异,标识好,
便于写代码时使用,通讯是paraent_pp.send(),对应一个child_pp.recv() 一个发送对应一个回收,底层是socket本机通讯实现的。
数据共享:
以下必须在__name__=="__main__"的情况下运行,也就是作为主进程运行时才可以创建。
mmm= multiprocessing.Manager() # 这个必须是在主进程执行,所以__name__=="__main__"才能使用,
# 共享数据用的对象,
# 可以生成共享的相应对象:
# list, dict, Namespace, Lock, RLock, Semaphore,
# BoundedSemaphore, Condition, Event, Barrier, Queue, Value ,Array
md = mmm.dict() #生成共享字典
ml = mmm.list() #生成共享列表
ml.append("[%s]主进程加的"%os.getpid()) #主进程向共享列表中修改数据
md[os.getpid()]="[%s]主进程加的"%os.getpid() #主进程向共享字典中修改数据
共享资源必须传递给子进程,子进程才可以使用。
进程锁:使用multiprocessing.Lock(),用法和线程锁一致,但是其实实际意义不大,因为进程本来就是资源独立,不存在资源征用,
但是,屏幕是共享的,保证输出完整,用这个锁是ok的
重点:进程池使用multiprocessing.Pool
声明 pool=multiprocessing.Pool(processes=2) #定义一个进程池,每次执行两个进程的进程池
使用:
for i in range(20):
# pool.apply(func=go_process,args=(i,)) #进程池中开始执行进程,这个是串行执行,不支持回调函数
pool.apply_async(func=go_process,args=(i,),callback=go_back) #一般用这个,就是并行执行定义时定义的并行进程个数,支持回调函数
关闭:
pool.close() #先写关闭进程池
pool.join() #再写等待子进程完成,必须这个顺序,原因不明
import multiprocessing #多进程模块 import time,os os.getpid() #获取当前进程的进程ID os.getppid() #获取当前进程的父进程ID qq=multiprocessing.Queue() #这是个进程queue,语法与线程queue (import queue的那个)是一样的。实现进程间的通信 p_pp,c_pp=multiprocessing.Pipe() #用于进城之间通信的另一个方式,管道,生成了管道的两端,没有区别,父进程一个,子进程一个 def run(dict,llll,pp,qq_func,name): dict[os.getpid()]="[%s]子进程加的"%os.getpid() #子进程向共享字典中修改数据 llll.append("[%s]子进程加的"%os.getpid()) #子进程向共享列表中修改数据 qq_func.put("队列数据:子进程ID[%s]"%os.getpid()) #子进程向共享队列中修改数据 print("我是子进程,我的进程ID:",os.getpid()) print("那么我的父进程ID是:",os.getppid()) pp.send("这是子进程[%s]通过pipe发过来的信息"%os.getpid()) #子进程向进程通讯管道中发送数据 time.sleep(2) print("i'm %s"%name) if __name__=="__main__": p_list=[] mmm= multiprocessing.Manager() # 这个必须是在主进程执行,所以__name__=="__main__"才能使用, # 共享数据用的对象, # 可以生成共享的相应对象: # list, dict, Namespace, Lock, RLock, Semaphore, # BoundedSemaphore, Condition, Event, Barrier, Queue, Value ,Array md = mmm.dict() #生成共享字典 ml = mmm.list() #生成共享列表 ml.append("[%s]主进程加的"%os.getpid()) #主进程向共享列表中修改数据 md[os.getpid()]="[%s]主进程加的"%os.getpid() #主进程向共享字典中修改数据 for i in range(10): p=multiprocessing.Process(target=run,args=(md,ml,c_pp,qq,"kk[%s]"%i,)) #与多线程语法差不多,这样就生成了进程实例, p.start() #启动子进程 p_list.append(p) print("我是主进程,我的进程ID:", os.getpid()) for mp in p_list: mp.join() print(md) #显示共享字典最终数据 print(ml) #显示共享列表最终数据 i=0 while i<len(p_list): print(qq.get()) print(p_pp.recv()) #主进程从进程通道中获取数据 i+=1 print(qq.qsize())
进程池:
def go_process(m): #子进程执行的函数 time.sleep(2) print("参数:[%s],子进程的pid:%s"%(m,os.getpid())) def go_back(m): #回调函数 print("这是回调函数,参数[%s]执行的进程是:%s"%(m,os.getpid())) if __name__=="__main__": pool=multiprocessing.Pool(processes=2) #定义一个进程池,每次执行两个进程的进程池 for i in range(20): # pool.apply(func=go_process,args=(i,)) #进程池中开始执行进程,这个是串行执行,不支持回调函数 pool.apply_async(func=go_process,args=(i,),callback=go_back) #一般用这个,就是并行执行定义时定义的并行进程个数,支持回调函数 pool.close() #先写关闭进程池 pool.join() #再写等待子进程完成,必须这个顺序,原因不明