进程通信、消费者模型和线程
一.进程间通信
队列:先进先出
堆栈:先进后出
一般利用队列实现进程间的通信
from multiprocessing import Queue q = Queue(5) # 产生一个最多能够存放五个数据的队列 q.put(1) # 往队列中存放数据, # 如果存放的数据个数大于队列最大存储个数,程序会阻塞 print(q.full) # 判断队列是否饱和 q.get() # 取数据,get一次就取一个 q.get_nowait() # 在队列有数据的情况下,与get取值相同 # 在队列没有数据的情况下,取值直接报错 print(q.empty()) # 判断队列是否为空,在并发情况下,判断不准确 print(q.get()) # 如果队列为空,get就会在原地等待队列中有数据过来
二.基于队列实现进程间通信
from multiprocessing import Queue, Process def producer(q): q.put('hello world') def consumer(q): print(q.get()) if __name__ =='__main__': q.Queue() # 生成一个队列对象 p1 = Process(target=producer,args=(q,)) c1 = Process(target=consumer,args=(q,)) p1.start() c1.start()
三.生产者消费者模型
生产者消费者模型:
生产者: 生产数据的程序
消费者: 处理数据的程序
解决供需不平衡的问题
定义一个队列,用来存放固定数量的数据
解决一个生产者和消费者不需要直接交互,两者通过队列进行数据传输
Queue(队列) = 管道 + 锁
1.Queue方法
from multiprocessing import Process,Queue,JoinableQueue import time import random def produce(name,food,q): for i in range(5): data = '%s 做了 %s%s' % (name,food,i) time.sleep(random.randint(1,3)) print(data) q.put(data) # 将生产的数据放入队列中 def consumer(name,q): while True: data:str = q.get() if data is None:break time.sleep(random.randint(1,3)) data = data.replace('了', '的') print('%s 吃了 %s' % (name, data)) if __name__ == '__main__': q = Queue() # 生成一个队列对象 p1 = Process(target=produce,args=('egon', '包子', q,)) p2 = Process(target=produce,args=('tank', '小笼', q,)) c1 = Process(target=consumer,args=('owen', q,)) c2 = Process(target=consumer,args=('jason', q,)) p1.start() p2.start() c1.start() c2.start() p1.join() # 等待生产者生产完所有的数据 p2.join() # 等待生产者生产完所有的数据 # 在生产者生产完数据之后,往队列里面放一个提示性的消息,告诉消费者已经没有数据,你走吧,不要等了 q.put(None) q.put(None)
2.JoinableQueue方法
from multiprocessing import Process, JoinableQueue import time import random def produce(name, food, q): for i in range(5): data = '%s 做了 %s%s' % (name, food, i) time.sleep(random.randint(1, 3)) print(data) q.put(data) # 将生产的数据放入队列中 def consumer(name, q): while True: data: str = q.get() if data is None: break time.sleep(random.randint(1, 3)) data = data.replace('了', '的') print('%s 吃了 %s' % (name, data)) q.task_done() # 告诉你的队列,你已经将数据取出并且处理完毕 if __name__ == '__main__': q = JoinableQueue() # 生成一个队列对象 p1 = Process(target=produce, args=('egon', '包子', q,)) p2 = Process(target=produce, args=('tank', '小笼', q,)) c1 = Process(target=consumer, args=('owen', q,)) c2 = Process(target=consumer, args=('jason', q,)) p1.start() p2.start() c1.daemon = True c2.daemon = True c1.start() c2.start() # 等待生产者生产完所有的数据 p1.join() p2.join() q.join() # 等待队列中数据全部取出
四.线程
1.什么是线程
进程:资源单位(只申请内存空间)
线程:执行单位(执行代码)
注意: 每一个进程中都会自带一个线程
2.为什么要有线程
开启一个进程:
申请内存空间 耗时
将代码拷贝到申请的内存空间中 耗时
开启一个线程
不需要申请内存空间 速度快
不需要拷贝代码 省时
总结:开线程的开销远远小于进程的开销!!!
五.开启线程的两种方式
1.Thread模块开始线程
from threading import Thread import time def task(name): print('%s is running' % name) time.sleep(1) print('%s is running' % name) t = Thread(target=task,args=('egon',)) t.start() print('主')
2.自定义模块继承Thread模块开始线程
from threading import Thread import time class MyThread(Thread): def __init__(self,name): super().__init__() # 重写功能,以防父类功能缺少执行 self.name = name def run(self): print('%s is running' % self.name) time.sleep(1) print('%s is running' % self.name) t = MyThread('egon') t.start() print('主')
六.线程之间数据共享
from threading import Thread x = 100 def task(): global x x = 1 t = Thread(target=task) t.start() t.join() print(x)
七.线程互斥锁
from threading import Thread, Lock import time x = 100 mutex = Lock() def task(): global x mutex.acquire() temp = x time.sleep(0.1) x = temp - 1 mutex.release() t_list = [] for i in range(100): t = Thread(target=task) t_list.append(t) t.start() for i in t_list: i.join() print(x)
八.线程对象其他属性和方法
from threading import Thread, active_count, current_thread import os, time def task(): print('%s is running' % current_thread().name,os.getpid()) time.sleep(1) print('%s is done' % os.getpid()) t = Thread(target=task) t.start() print(active_count()) print('主', os.getpid(),current_thread().name)
九.守护线程
from threading import Thread import time def task(): print('is running') time.sleep(2) print('is over') t = Thread(target=task) t.daemon = True t.start() print('主')