生产者消费者模型
进程:
生产者消费者模型
编程思想, 模型, 设计模式, 理论等等, 都是交给你一种编程的方法, 以后遇到类似的情况, 套用即可
生产者消费者模型三要素
生产者: 产生数据的
消费者: 接收数据做进一步处理的
容器: 盆(队列)
队列容器的作用
起到缓冲的作用, 平衡生产力与消费力, 解耦
实例
import timeimport randomfrom multiprocessing import Process, Queuedef producer(q, name): for i in range(1, 6): time.sleep(random.randint(1, 2)) res = f"{i}号包子" q.put(res) print(f"生产者{name} 生产了{res}")def consumer(q, name): while 1: try: food = q.get(timeout=3) time.sleep(random.randint(1, 3)) print(f"\033[31;0m 消费者{name} 吃了{food} \033[0m") except Exception: returnif __name__ == '__main__': q = Queue() p1 = Process(target=producer, args=(q, "孙宇")) p2 = Process(target=consumer, args=(q, "海狗")) p1.start() p2.start()"""生产者孙宇 生产了1号包子生产者孙宇 生产了2号包子 消费者海狗 吃了1号包子 生产者孙宇 生产了3号包子 消费者海狗 吃了2号包子 生产者孙宇 生产了4号包子生产者孙宇 生产了5号包子 消费者海狗 吃了3号包子 消费者海狗 吃了4号包子 消费者海狗 吃了5号包子 """
开启线程的两种方式
进程是资源单位, 线程是执行单位
什么是线程
一条流水线的工作流程.
进程:
在内存中开启一个进程空间, 然后将主进程的所有的资源数据复制一份, 然后调用CPU去执行这些代码
具体描述进程:
在内存中开启一个进程空间, 然后将主进程的所有的资源数据复制一份, 然后调用线程去执行代码
执行流程
主线程子线程没有地位之分, 但是一个主线程在执行, 执行完, 要等待其他非守护子线程执行完之后, 才能结束主线程, 结束本进程
# 第一种方式from threading import Threadimport timedef task(name): print(f"{name} is running") time.sleep(1) print(f"{name} is gone")if __name__ == '__main__': t1 = Thread(target=task, args=("海狗",)) t1.start() print("===主线程") # 线程没有主次之分"""李业 is running===主线程李业 is gone""" # 第二种方式from threading import Threadimport timeclass MyThread(Thread): def __init__(self, name, l1, s1): super(MyThread, self).__init__() self.name = name self.l1 = l1 self.s1 = s1 def run(self): print(f"{self.name} is running") time.sleep(1) print(f"{self.name} is gone")if __name__ == '__main__': t1 = MyThread("李业", [1,2,3], "180") t1.start() print("===主线程")"""李业 is running===主线程李业 is gone"""
多线程与多进程开启速度区别
from multiprocessing import Processimport timedef work(): print("hello")if __name__ == '__main__': start_time = time.time() lst = [] for i in range(10): t = Process(target=work) t.start() lst.append(t) for i in lst: i.join() print(time.time() - start_time)"""hellohellohellohellohellohellohellohellohellohello1.004307746887207"""# 多线程from threading import Threadimport timedef task(): print("hello")if __name__ == '__main__': start_time = time.time() lst = [] for i in range(10): t = Thread(target=task) t.start() lst.append(t) for i in lst: i.join() print(time.time() - start_time)"""hellohellohellohellohellohellohellohellohellohello0.0019998550415039062"""
开启进程的开销非常大, 比开启线程的开销大很多.
开启线程的速度非常快, 要快几十倍到上百倍.
线程进程pid
# 进程pidfrom multiprocessing import Processimport osdef task(): print(f"子进程:{os.getpid()}") print(f"主进程:{os.getppid()}")if __name__ == '__main__': p1 = Process(target=task) p2 = Process(target=task) p1.start() p2.start() print(f"==主:{os.getpid()}")"""==主:51060子进程:51128主进程:51060子进程:42856主进程:51060"""# 线程pidfrom threading import Threadimport osdef task(): print(os.getpid())if __name__ == '__main__': t = Thread(target=task) t1 = Thread(target=task) t.start() t1.start() print(f"===主线程:{os.getpid()}")"""5176851768===主线程:51768"""# 多线程在同一个进程内, 所以pid都一样
同一进程内线程是共享数据的
线程与线程之间可以共享数据, 进程与进程之间需要借助队列等方法实现通信
同一进程内的资源数据对于这个进程内的多个线程来说是共享的
线程的应用
并发: 一个CPU看起来像是同时执行多个任务
单个进程开启三个线程, 并发的执行任务
开启三个进程并发的执行任务
文本编辑器:
1.输入文字
2.在屏幕上显示
3.保存在磁盘中
开启多线程就非常简单了:
数据共享, 开销小, 速度快
from threading import Threadx = 3def task(): global x x = 100if __name__ == '__main__': t1 = Thread(target=task) t1.start() t1.join() print(f"===主线程{x}") """===主线程100"""
线程的其他方法
from threading import Thread, current_thread, enumerate, activeCountimport osimport timex = 3def task(): time.sleep(1) print(666)if __name__ == '__main__': t1 = Thread(target=task) t2 = Thread(target=task) t1.start() t2.start() print(t1.isAlive()) # 判断子线程是否存活 print(t1.getName()) # 获取子线程名字 t1.setName("子进程-1") # 修改子线程名字 print(t1.name) # 获取子线程的名字 *** print(current_thread()) # 获取当前线程的内容 print(enumerate()) # 获取当前进程下的所有线程,以列表形式展示 print(activeCount()) # 获取当前进程下的所有存活线程的数量 print(os.getpid()) """TrueThread-1子进程-1<_MainThread(MainThread, started 60668)>[<_MainThread(MainThread, started 60668)>,, ]361048666666"""
join 与 守护线程
守护线程, 等待非守护子线程以及主线程结束之后, 结束
from threading import Threadimport timedef say_hi(name): print("你滚") time.sleep(2) print(f"{name} say hello")if __name__ == '__main__': t = Thread(target=say_hi, args=("egon",)) # t.setDaemon(True) # 必须在t.start()前设置, 两种方法都可以 t.daemon = True t.start() print("主线程") # 注意 线程的开启速度比进程要快的多 """你滚主线程"""
from threading import Threadimport timedef foo(): print(123) time.sleep(1) print("end123") def bar(): print(456) time.sleep(3) print("end456") t1=Thread(target=foo)t2=Thread(target=bar)t1.daemon=Truet1.start()t2.start()print("main-------") """123456main-------end123end456"""
互斥锁
from threading import Threadimport timeimport randomx = 100def task(): global x temp = x time.sleep(random.randint(1, 3)) temp = temp - 1 x = tempif __name__ == '__main__': l1 = [] for i in range(100): t = Thread(target=task) l1.append(t) t.start() for i in l1: i.join() print(f'主线程{x}')"""主线程99"""# 多个任务共抢一个数据, 为了保证数据的安全性, 要让其串行from threading import Threadfrom threading import Lockimport timex = 100def task(lock): lock.acquire() global x temp = x temp = temp - 1 x = temp lock.release()if __name__ == '__main__': mutex = Lock() l1 = [] for i in range(100): t = Thread(target=task,args=(mutex,)) l1.append(t) t.start() time.sleep(3) print(f'主线程{x}')"""主线程0"""