为什么需要通信
在生产者和消费者的模型中,如果有一个生产者和多个消费者,消费者之间就需要线程节的通信,避免重复读取同一个数据。
通信方法
共享变量
共享变量介绍
共享变量是最简单粗暴的方式进行多线程之间的通信,使用Python的 global
关键字,把一个list变为全局变量,然后对这个全局变量进行添加和获取。
优点就是简单粗暴,浅显易懂,容易写代码,容易理解,同样缺点也有很多。
缺点:
操作不是线程安全的,即使判断的时候变量不是空的,获取的时候也有可能变成空的。
实现
#线程间的通信
#1.共享变量
import threading
import time
itemList = []
#定义消费者
def Consumer(url):
global itemList
while True:
if len(itemList):
i = itemList.pop()
time.sleep(2)
print('Consumer',i)
#定义生产者
def Producer(url):
global itemList
for i in range(10):
print('Producer', url + str(i))
itemList.append(url+str(i))
if __name__ == "__main__":
thread1 = threading.Thread(target=Producer,args=("www.baidu.com",))
threadList = [threading.Thread(target=Consumer,args=("",) ) for i in range(2)]
thread1.start()
thread1.join()
for thead in threadList:
thead.start()
结果:
消息队列(Queue)实现通信
消息队列介绍
比起共享变量,Queue本身是线程安全的,并且可作为参数传入进不同的线程,让代码更简单易懂。
blcok
参数为是否阻塞,如果是True就是阻塞式的,如果当前没有值,阻塞式的就会一直等待新的东西出现。阻塞式的可以比非阻塞式的消耗更少的计算资源,因为不会再空队列的时候一直执行 while True
。
实现
import threading
import time
from queue import Queue
itemList = []
def Consumer(url,queue):
while True:
i = queue.get(block = True)
time.sleep(2)
print('Consumer',i)
def Producer(url,queue):
for i in range(10):
print('Producer', url + str(i))
queue.put(url+str(i))
if __name__ == "__main__":
urlQueue = Queue(maxsize=200)
thread1 = threading.Thread(target=Producer,args=("www.baidu.com",urlQueue))
threadList = [threading.Thread(target=Consumer,args=("",urlQueue) ) for i in range(2)]
thread1.start()
thread1.join()
for thead in threadList:
thead.start()
运行结果和全局变量类似,但是这种方法效率更高。