python 进程通信 day06

2018.8.13

目录

multiprocessing

创建自定义进程类

进程池技术

进程间通信(IPC)


day05回顾

  1. 孤儿进程 僵尸进程
  2. 聊天室
  3. multiprocessing
    Process   start   join
    创建多个子进程示例:
    from multiprocessing import Process 
    from time import sleep 
    import os 
    
    def th1():
        sleep(3)
        print("吃饭")
        print(os.getpid(),'---',os.getppid())
    def th2():
        sleep(4)
        print("睡觉")
        print(os.getpid(),'---',os.getppid())
    def th3():
        sleep(2)
        print("打豆豆")
        print(os.getpid(),'---',os.getppid())
    
    things = [th1,th2,th3]
    process = []
    
    for th in things:
        p = Process(target = th)
        process.append(p)  #保存进程对象
        p.start()
    
    #回收进程
    for i in process:
        i.join()

day06

multiprocessing

Process(target,name,args,kwargs)

  1. name:给进程起名字
    没有起名字,默认为Process-1 Process-2...
    p.name 可以获取进程名称
  2. args :以元组的形式给target函数传参
  3. kwargs:以字典的形式给对应的函数传参

进程对象的其他属性方法

  • p.start()   p.join()
  • p.name 进程名
  • p.pid:创建新的进程的PID号
     
  • p.is_alive() 判断进程是否处于alive状态 返回值是True或者False
    from multiprocessing import Process 
    from time import sleep
    
    def worker(sec,name):
        for i in range(3):
            sleep(sec)
            print("I'm %s"%name)
            print("I'm working...")
    
    p = Process(target = worker,name = "Worker",\
        args = (2,),kwargs = {'name':'Alex'})
    p.start()
    
    print(p.name) #返回name给的参数
    print("Child PID:",p.pid) # p进程的进程号
    print("is alive?  ",p.is_alive()) #判断进程状态
    
    p.join()
    print("is alive?  ",p.is_alive())
    
    
    #Worker
    #Child PID: 20062
    #is alive?   True
    #I'm Alex
    #I'm working...
    #I'm Alex
    #I'm working...
    #I'm Alex
    #I'm working...
    #is alive?   False
    
    
  • p.daemon
    默认值是False,
    如果设置为True,则主进程退出时,子进程也会结束
    daemon 属性设置要在start()前
    设置daemon为True 则一般不需要加join
    from multiprocessing import Process 
    from time import sleep,ctime 
    
    def tm1():
        while True:
            sleep(2)
            print(ctime())
    
    p = Process(target = tm1)
    
    p.daemon = True 
    
    p.start()
    print("main process over")

  cookie

  • 获取文件大小
    size = os.path.getsize('./timg.jpeg')
    功能:获取一个文件的大小
    参数:文件

  注意:

  • 如果多个子进程拷贝同一个父进程中的对象,则多个子进程使用的是同一个对象(如文件对象,套接字,队列,管道...)
    如果是在创建子进程后单独创建的对象,则多个子进程各不相同

创建自定义进程类

  1. 编写类继承Process
  2. 在自定义类中加载父类__init__以获取父类属性,同时可以自定义新的属性
  3. 重写run方法,在调用start时自动执行该方法

     
  • 进程的缺点:
    进程在创建和销毁的过程中消耗的资源相对较多
  • 进程的优点:
    能并行执行多个任务,提高效率,创建方便,运行独立,不受其他进程影响,数据安全
    示例:
    from multiprocessing import Process 
    import time 
    
    class ClockProcess(Process):
        def __init__(self,value):
            #调用父类init
            super().__init__()
            self.value = value 
        #重写run方法
        def run(self):
            for i in range(5):
                time.sleep(self.value)
                print("The time is {}".format(time.ctime()))
    
    p = ClockProcess(2)
    #自动执行run
    p.start()
    
    p.join()
    

进程池技术

  产生原因:

  • 如果有大量的任务需要多进程完成。而任务周期又比较短且需要频繁创建。此时可能产生大量进程频繁创建销毁的情况,消耗计算机资源较大

  使用方法:

  1. 创建进程池,在池内放入适当数量的进程
  2. 将事件封装函数,放入到进程池队列
  3. 事件不断运行,知道所有放入进程池事件运行完成
  4. 关闭进程池,回收进程

  from multiprocessing  import  Pool

  • Pool(processes)
  • 功能:创建进程池对象
  • 参数:进程数量
  • 返回:进程池对象

     
  • pool.apply_async(fun,args,kwds)
  • 功能 : 将事件放入进程池执行
  • 参数 : fun,要执行的事件函数
                args  给fun用元组传参
                kwds  给fun用字典传参
  • 返回值 :返回事件对象 通过get()方法获取事件函数返回值

     
  • pool.apply(fun,args,kwds)
  • 功能 : 将事件放入进程池执行
  • 参数 : fun,要执行的事件函数
                args  给fun用元组传参
                kwds  给fun用字典传参

     
  • pool.close()
  • 功能:关闭进程池,无法再加入事件

     
  • pool.join()
  • 功能:回收进程池
     
  • pool.map(func,iter)
  • 功能:将要执行的事件放入到进程池
  • 参数:func 要执行的函数
               iter 迭代对象,给func传参
  • 返回值:返回func的返回值列表
    Pool示例:
    from multiprocessing import Pool 
    from time import sleep,ctime 
    
    def worker(msg):
        sleep(2)
        print(msg)
        return ctime()
    
    #创建进程池对象
    pool = Pool(processes = 4)
    
    result = []
    for i in range(10):
        msg = "hello %d"%i 
        #将事件放入进程池
        r = pool.apply_async(func = worker,args = (msg,))
        result.append(r)
        
        #同步执行
        # pool.apply(func = worker,args = (msg,))
    
    #关闭进程池
    pool.close()
    #回收
    pool.join()
    
    #获取事件函数返回值
    for i in result:
        print(i.get())


    Pool.map示例:
    from multiprocessing import Pool
    import time 
    
    def fun(n):
        time.sleep(1)
        print("执行 pool map事件",n)
        return n ** 2 
    
    pool = Pool(4)
    
    #在进程池放入6个事件
    r = pool.map(fun,range(6))
    print("返回值列表:",r)
    
    pool.close()
    pool.join()

     

进程间通信(IPC)

由于进程间空间独立,资源无法共享,此时在进程间通信就需要专门的通信方法。

进程间通信方法:管道,消息队列,共享内存,信号,信号量,套接字

  管道通信(pipe)

  • 管道:在内存中开辟一块空间,形成管道结构多个进程使用同一个管道,即可通过对管道的读写操作进行通信。

  multiprocess ---》 Pipe 

  • fd1,fd2 = Pipe(duplex = True)
    功能: 创建一个管道
    参数: 默认表示双向管道
                如果设置为False 则为单向管道
    返回值:两个管道对象,分别表示管道的两端
                  如果双向管道,fd1 fd2都可以进行读写操作
                  如果是单向管道,则fd1 只可读,fd2只可写
     
  • fd.recv()
    功能:从管道读取信息
    返回值:读取到的内容
    如果管道为空则阻塞
     
  • fd.send(data)
    功能:向管道写入内容
    参数:要写入的内容
    管道满时会阻塞
    *可以写入几乎所有的python数据
    示例:
    from multiprocessing import Process,Pipe
    import os,time 
    
    #创建管道
    fd1,fd2 = Pipe(False)
    
    def fun(name):
        time.sleep(3)
        #向管道写入内容
        fd2.send("hello" + str(name)) 
    
    jobs = []
    for i in range(5):
        p = Process(target = fun,args = (i,))
        jobs.append(p)
        p.start()
    
    while True:
        #从管道读取内容
        data = fd1.recv()
        print(data)
    
    for i in jobs:
        i.join()

  消息队列

  • 队列:先进先出
    在内存中开辟队列结构空间,对多个进程可见,多个进程操作同一个队列对象可以实现消息的存取工作

  创建队列

  • q = Queue(maxsize = 0)
    功能 :创建队列对象
    参数 :maxsize  默认表示根据系统分配队列空间
               如果传入一个正整数则表示最多存放多少条消息
    返回值 :队列对象

     
  • q = put(data,[block,timeout])
    功能:向队列中存入消息
    参数:data 存入的消息(支持python数据类型)
               block 默认为True 表示当队列满时阻塞
               设置为False 则为非阻塞
               timeout 超时时间

     
  • data = q.get([block,timeout])
    功能:获取队列消息
    参数:block 默认为True 表示队列空时阻塞
               设置False 则表示非阻塞
    返回值:返回获取到的消息

     
  • q.full() 判断队列是否为满
  • q.empty() 判断队列是否为空
  • q.qsize() 获取队列中消息数量
  • q.close() 关闭队列
    示意:
    from multiprocessing import Queue 
    from time import sleep 
    
    #创建队列
    q = Queue(3)
    
    q.put(1)
    sleep(0.1)
    print(q.empty())
    q.put("Process Queue")
    q.put([1,2,3])
    print(q.full())  
    #如设置为非阻塞则产生Full异常
    # q.put(666,False) #非阻塞
    # q.put(666,True,3)  #超时
    print(q.get())
    print(q.qsize()) #查看消息数量
    q.close()
    示例:
    from multiprocessing import Process,Queue
    import time 
    
    #创建队列
    q = Queue()
    
    def fun1():
        time.sleep(1)
        q.put({'name':'Abby','passwd':'123'})
    
    def fun2():
        print("收到消息:",q.get())
    
    p1 = Process(target = fun1)
    p2 = Process(target = fun2)
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    

     

  共享内存

  • 在内存中开辟一段空间,存储数据,对多个进程可见。每次写入共享内存中的内容都会覆盖之前的内容,对内存的读操作页不会改变内存中的内容

  from multiprocessing Value Array

  • shm = Value(ctype,obj)
    功能:开辟共享内存空间
    参数:ctype 字符串  要转变的c的类型
               obj 共享内存初始数据
    返回值:返回共享内存对象
    shm.value 表示共享内存中的值
    from  multiprocessing import Process,Value 
    import time 
    import random  
    
    #创建共享内存
    money = Value('i',6000)
    
    #存钱
    def deposite():
        for i in range(100):
            time.sleep(0.05)
            #对value的修改就是对共享内存的修改
            money.value += random.randint(1,200)
    #花销
    def withdraw():
        for i in range(100):
            time.sleep(0.04)
            #对value的修改就是对共享内存的修改
            money.value -= random.randint(1,200)
    
    d = Process(target = deposite)
    w = Process(target = withdraw)
    
    d.start()
    w.start()
    
    d.join()
    w.join()
    print(money.value)

     
  • shm = Array(ctype,obj)
    功能:开辟共享内存空间
    参数:ctype 要转换的的数据类型
               obj 要存入共享内存的数据,
               列表,字符串 表示要存入的内容,要求类型相同
               整数,表示要开辟几个单元的空间
    返回值:返回共享内存对象,可迭代对象
    from multiprocessing import Process,Array
    import time 
    
    #创建共享内存
    shm = Array('c',b"hello") #字符类型要求是bytes
    
    #开辟5个整形单元的共享内存空间
    # shm = Array('i',5)
    
    def fun():
        for i in shm:
            print(i)
        shm[0] = b"H"
    
    p = Process(target = fun)
    p.start()
    p.join()
    
    print(shm.value) #从首地址打印字符串
    # for i in shm:
    #     print(i)
    
      管道 消息队列 共享内存
    开辟空间 内存 内存 内存
    读写方式

    两端读写

    双向/单向

    先进先出 每次覆盖上次内容
    效率 一般 一般 较快
    应用 多用于父子进程 应用灵活广泛

    复杂,需要同步,

    互斥操作

作业:

  • 熟练进程间通信和进程池的使用
  • 复习类的使用

 
 

猜你喜欢

转载自blog.csdn.net/qq_42584444/article/details/81624433