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()     #再写等待子进程完成,必须这个顺序,原因不明

 

posted @ 2017-12-20 15:05  王玥  阅读(232)  评论(0编辑  收藏  举报