37 day of python
内容回顾
数据隔离
进程和进程之间内存中的数据是互相隔离的
多进程起socket
守护进程
守护进程会随着主进程的代码结束而结束
报活
锁 Lock 互斥锁
acquire / release
信息量
锁 + 计数器
事件 : 通过一个标记来控制对多个进程进行同步控制
在某个地方wait是否阻塞的行为是根据事件对象内部的一个标记来决定的
在事件对象中提供的方法可以修改这个标记的状态
今日内容
进程之间的通信
队列 *****
管道 ***
进程之间的数据共享 *
进程池 *****
队列 先进先出FIFO - 维护秩序的时候用的比较多 买票 秒杀
# from queue import Queue # q = Queue(5) # print(q.qsize()) # q.put(12) # q.put(3) # q.put(4) # q.put(4) # q.put(4) # 满了会阻塞 # q.put_nowait() # 满了就会报错 # print('***',q.qsize()) # print(q.get()) # print(q.get()) # print(q.get()) # print(q.get()) # 没有值的时候会阻塞 # print(q.get_nowait()) # 当有值的时候取值 # print(q.get_nowait()) # 没有值的时候会报错 # print(q.full()) # print(q.empty()) # print(q.qsize()) # print(q.get()) # print(q.get()) # print(q.qsize())
栈 先进先出 - 算法
三级菜单
计算文件夹的总大小
进程之间得通信 - IPC
队列
from multiprocessing import Queue q = Queue()
在多进程中 q.empty() q.full()是不准的
q.empty()
q.full()
q.put_nowait()
q.put()
q.get_nowait()
q.get()
主进程放 子进程取
from multiprocessing import Queue,Process def funa(q): for i in range(5): print(q.get()) if __name__ == '__main__': q = Queue() p = Process(target=funa,args=(q,)) for i in range(5): q.put(i) p.start()
子进程放 另一个子进程取
from multiprocessing import Queue,Process def con(q): print(q.get()) def ad(q): q.put(123) if __name__ == '__main__': q = Queue() p = Process(target=con,args=(q,)) p.start() p1 = Process(target=ad, args=(q,)) p1.start()
生产者消费者模型 - 解决创造(生产)数据和处理(消费)数据的效率不平衡问题
把创造数据 和 处理数据放在不同的进程中,
根据他们的效率来调整进程的个数
生产数据快 消费数据慢 内存空间的浪费
消费数据快 生产数据慢 效率低下
import time import random from multiprocessing import Process,Queue def consumer(q,name): while True: food = q.get() if food == 'stop':break print('%s 吃了 %s'%(name,food)) time.sleep(random.random()) def producer(q,name,food,n=10): for i in range(n): time.sleep(random.random()) fd = food+str(i) print('%s 生产了 %s'%(name,fd)) q.put(fd) if __name__ == '__main__': q = Queue(10) c1 = Process(target=consumer,args=(q,'alex')) c1.start() c2 = Process(target=consumer,args=(q,'alex')) c2.start() p1 = Process(target=producer,args=(q,'太白','泔水')) p1.start() p2 = Process(target=producer, args=(q, 'egon', '泔水')) p2.start() p1.join() p2.join() q.put('stop') q.put('stop')
让consumer停下来的方法
在所有生产者结束生产之后 向队列中放入一个结束符
有几个consumer就向队列中放几个结束符
在消费者消费的过程中,接收到结束符,就结束消费的进程
import time import random from multiprocessing import JoinableQueue,Process # join 阻塞 def consumer(q,name): while True: food = q.get() print('%s 吃了 %s'%(name,food)) time.sleep(random.random()) q.task_done() def producer(q,name,food,n=10): for i in range(n): time.sleep(random.random()) fd = food+str(i) print('%s生产了%s'%(name,fd)) q.put(fd) q.join() if __name__ == '__main__': q = JoinableQueue() c1 = Process(target=consumer,args=(q,'alex')) c1.daemon = True c1.start() c2 = Process(target=consumer, args=(q, 'alex')) c2.daemon = True c2.start() p1 = Process(target=producer,args=(q,'太白','泔水')) p1.start() p2 = Process(target=producer, args=(q, 'egon', '鱼刺')) p2.start() p1.join() p2.join()
只有multiprocessing中的队列 才能帮助你 实现IPC
永远不可能出现数据不安全的情况,多个进程不会同时取走同一个进程
提供给你的方法
put
get
put_nowait
get_nowait
empty - 在多进程内不可靠
full - 在多进程内不可靠
qsize - 在多进程内不可靠
由于先进先出的特点+进程通信的功能+数据进程安全,经常用它来完成进程之间的通信
生产者消费者模型
生产者和消费者的效率平衡的问题
内存的控制 - 队列的长度限制
让消费者自动停下来
JoinableQueue
在消费数据的时候 task_done
在生产端\主进程 join
管道
队列就是基于管道实现的
队列 数据安全的
管道 数据不安全的
队列 = 管道 + 锁
from multiprocessing import Pipe left,right = Pipe() left.send('aaa') print(right.recv())
from multiprocessing import Pipe,Process def consumer(left,right): left.close() while True: try: print(right.recv()) except EOFError: break if __name__ == '__main__': left,right = Pipe() p = Process(target=consumer,args=(left,right)) p.start() right.close() for i in range(10): left.send('hello') left.close()
EOF异常的触发
在这一个进程中 如果不在用这个断点,应该close
这一在recv的时候,如果没有消息可接收,recv方法会一直阻塞。
如果其他端点都被关闭了,就能够知道不会在有新的消息传进来
此时就不会在这里阻塞等待,而是抛出一个EOFError
* close并不是关闭了整个管道,而是修改了操作系统对管道端点的引用计数的处理
以下是错误代码:代表管道数据不安全
from multiprocessing import Process,Pipe def consumer(p,name): produce,consume=p produce.close() while True: try: baozi = consume.recv() print('%s 收到包子:%s' %(name,baozi)) except EOFError: break def producer(p,seq=10): produce,consume=p consume.close() for i in range(seq): produce.send(i) if __name__ == '__main__': produce,consume=Pipe() for i in range(5): c = Process(target=consumer,args=((produce,consume),'c1')) c.start() for i in range(5): p = Process(target=producer,args=((produce,consume))) p.start() producer((produce,consume)) produce.close() consume.close()
from multiprocessing import Manager,Process,Lock def work(d,lock): with lock: d['count'] -= 1 if __name__ == '__main__': lock = Lock() m = Manager() dic=m.dict({'count':100}) p_l = [] for i in range(100): p = Process(target=work,args=(dic,lock)) p_l.append(p) p.start() for p in p_l: p.join() print(dic)
with as 的机制
__enter__
__exit__
开启进程慢
几个CPU就能同时运行几个进程 进程的个数不是无限开启的
100个任务
进程池
如果必须用多个进程
且是高计算型 没有IO 型的程序
希望并行 最充分的使用CPU
import os import time from multiprocessing import Pool def func(i): time.sleep(0.1) print(os.getpid(),i) if __name__ == '__main__': p = Pool(5) for i in range(20): p.apply_async(func,args=(i,)) p.close() p.join()
IPC通信
队列 管道+锁
管道 是队列的底层
数据共享 _ 进程就是数据隔离的
Manager模块
数据类型 都能够进行数据共享
一部分都是不加锁 不支持数据进程安全
不安全的解决办法 加锁
进程池
进程不能无限开 会给操作系统调度增加负担
且真正能被同时执行的进程最多也就和CPU个数相同等
进程的开启和销毁都要消耗资源和时间

浙公网安备 33010602011771号