2018.8.13
目录
day05回顾
- 孤儿进程 僵尸进程
- 聊天室
- 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)
- name:给进程起名字
没有起名字,默认为Process-1 Process-2...
p.name 可以获取进程名称 - args :以元组的形式给target函数传参
- 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 则一般不需要加joinfrom 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')
功能:获取一个文件的大小
参数:文件
注意:
- 如果多个子进程拷贝同一个父进程中的对象,则多个子进程使用的是同一个对象(如文件对象,套接字,队列,管道...)
如果是在创建子进程后单独创建的对象,则多个子进程各不相同
创建自定义进程类
- 编写类继承Process
- 在自定义类中加载父类__init__以获取父类属性,同时可以自定义新的属性
- 重写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()
进程池技术
产生原因:
- 如果有大量的任务需要多进程完成。而任务周期又比较短且需要频繁创建。此时可能产生大量进程频繁创建销毁的情况,消耗计算机资源较大
使用方法:
- 创建进程池,在池内放入适当数量的进程
- 将事件封装函数,放入到进程池队列
- 事件不断运行,知道所有放入进程池事件运行完成
- 关闭进程池,回收进程
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)
管道 消息队列 共享内存 开辟空间 内存 内存 内存 读写方式 两端读写
双向/单向
先进先出 每次覆盖上次内容 效率 一般 一般 较快 应用 多用于父子进程 应用灵活广泛 复杂,需要同步,
互斥操作
作业:
- 熟练进程间通信和进程池的使用
- 复习类的使用