多线程编程中,线程之间的通信是经常遇到的问题。Python中的Queue模块可以很好地解决这个问题。本文将详细讲解Queue模块的常用方法和使用场景。
Queue模块提供了FIFO队列、LIFO队列,以及优先级队列三种数据结构。
import queue
# 创建一个FIFO队列
fifo_queue = queue.Queue()
# 创建一个LIFO队列
lifo_queue = queue.LifoQueue()
# 创建一个优先级队列,其中元组的第一个元素为优先级,数字越小,优先级越高
priority_queue = queue.PriorityQueue()
# 将元素放入队列中,队列支持多线程安全,因此可以多个线程同时调用put方法
fifo_queue.put('Python')
lifo_queue.put('Python')
priority_queue.put((1, 'Python'))
# 取出队列中的元素,如果队列为空,get方法会阻塞,直到有元素可以取出
print(fifo_queue.get())
print(lifo_queue.get())
print(priority_queue.get()[1])
运行结果为:
Python
Python
Python
在多线程编程中,常常需要将数据从一个线程传递到另一个线程。Queue模块提供了线程安全的队列,可以很好地解决这个问题。
import queue
import threading
def producer(q):
for i in range(5):
q.put(i)
print('put', i)
# put方法在队列已满时会阻塞,因此需要调用q.join()等待队列为空
q.join()
def consumer(q):
while True:
data = q.get()
print('get', data)
q.task_done()
q = queue.Queue()
t1 = threading.Thread(target=producer, args=(q,))
t2 = threading.Thread(target=consumer, args=(q,))
t1.start()
t2.start()
t1.join()
t2.join()
在该示例中,producer
函数向队列中放入数据,consumer
函数从队列中取出数据并处理。在主线程中创建两个子线程,分别调用producer
和consumer
函数。在producer
函数中,调用Queue的put
方法向队列中放入数据,当队列已满时会阻塞。在consumer
函数中,循环调用Queue的get
方法取出队列中的元素,当队列为空时会阻塞,直到队列中有元素可以取出。队列的task_done
方法可以通知队列,表示该元素已经取出并处理完毕。
运行结果为:
put 0
put 1
put 2
put 3
put 4
get 0
get 1
get 2
get 3
get 4
Queue模块提供了阻塞式队列,当队列已满或队列为空时,队列的put
和get
方法会阻塞,直到队列中有元素可取或队列不再已满。以下是一个阻塞式队列的示例:
import queue
import threading
import time
import random
def producer(q):
while True:
data = random.randint(0, 10)
q.put(data)
print('put', data)
time.sleep(1)
def consumer(q):
while True:
data = q.get()
print('get', data)
time.sleep(2)
q = queue.Queue(5) # 创建一个队列,最多可以存放5个元素
t1 = threading.Thread(target=producer, args=(q,))
t2 = threading.Thread(target=consumer, args=(q,))
t1.start()
t2.start()
t1.join()
t2.join()
在该示例中,producer
函数无限循环地向队列中放入随机数值,在队列已满时阻塞。consumer
函数无限循环地取出队列中的值,在队列为空时阻塞。在主线程中创建producer
和consumer
两个子线程,分别调用producer
和consumer
函数,最多只能存放5个元素。
运行结果为:
put 0
get 0
put 1
put 2
get 1
put 10
get 2
put 9
get 10
put 2
get 9
put 7
get 2
put 4
get 7