生产者消费者模型
进程:
生产者消费者模型
编程思想, 模型, 设计模式, 理论等等, 都是交给你一种编程的方法, 以后遇到类似的情况, 套用即可
生产者消费者模型三要素
生产者: 产生数据的
消费者: 接收数据做进一步处理的
容器: 盆(队列)
队列容器的作用
起到缓冲的作用, 平衡生产力与消费力, 解耦
实例
import time
import random
from multiprocessing import Process, Queue
def 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" 33[31;0m 消费者{name} 吃了{food} 33[0m")
except Exception:
return
if __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 Thread
import time
def 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 Thread
import time
class 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 Process
import time
def 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)
"""
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
1.004307746887207
"""
# 多线程
from threading import Thread
import time
def 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)
"""
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
0.0019998550415039062
"""
开启进程的开销非常大, 比开启线程的开销大很多.
开启线程的速度非常快, 要快几十倍到上百倍.
线程进程pid
# 进程pid
from multiprocessing import Process
import os
def 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
"""
# 线程pid
from threading import Thread
import os
def task():
print(os.getpid())
if __name__ == '__main__':
t = Thread(target=task)
t1 = Thread(target=task)
t.start()
t1.start()
print(f"===主线程:{os.getpid()}")
"""
51768
51768
===主线程:51768
"""
# 多线程在同一个进程内, 所以pid都一样
同一进程内线程是共享数据的
线程与线程之间可以共享数据, 进程与进程之间需要借助队列等方法实现通信
同一进程内的资源数据对于这个进程内的多个线程来说是共享的
线程的应用
并发: 一个CPU看起来像是同时执行多个任务
单个进程开启三个线程, 并发的执行任务
开启三个进程并发的执行任务
文本编辑器:
1.输入文字
2.在屏幕上显示
3.保存在磁盘中
开启多线程就非常简单了:
数据共享, 开销小, 速度快
from threading import Thread
x = 3
def task():
global x
x = 100
if __name__ == '__main__':
t1 = Thread(target=task)
t1.start()
t1.join()
print(f"===主线程{x}")
"""
===主线程100
"""
线程的其他方法
from threading import Thread, current_thread, enumerate, activeCount
import os
import time
x = 3
def 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())
"""
True
Thread-1
子进程-1
<_MainThread(MainThread, started 60668)>
[<_MainThread(MainThread, started 60668)>, <Thread(子进程-1, started 55172)>, <Thread(Thread-2, started 62068)>]
3
61048
666
666
"""
join 与 守护线程
守护线程, 等待非守护子线程以及主线程结束之后, 结束
from threading import Thread
import time
def 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 Thread
import time
def 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=True
t1.start()
t2.start()
print("main-------")
"""
123
456
main-------
end123
end456
"""
互斥锁
from threading import Thread
import time
import random
x = 100
def task():
global x
temp = x
time.sleep(random.randint(1, 3))
temp = temp - 1
x = temp
if __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 Thread
from threading import Lock
import time
x = 100
def 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
"""