学科分类
目录

通过Queue类实现线程同步

Queue类表示一个FIFO(先进先出)队列,即先插入队列中的数据先获取,用于多个线程之间的信息传递。创建队列的方式比较简单,可以直接通过如下构造方法实现:

Queue(maxsize=0)

以上方法中只有一个maxsize参数,该参数指定了队列的长度,默认为0,表示队列的长度没有任何限制。

Queue类中提供了一些操作队列的常见方法,这些方法的功能说明如表1所示。

表1 Queue类的常见方法

方法 说明
qsize() 返回队列的大小
empty() 若队列为空返回True,否则返回False
full() 若队列已满返回True,否则返回False
put(item, block=True, timeout=None) 往队尾添加一个元素。该方法中共包含3个参数,item参数代表要添加的元素值;block参数代表是否阻塞队列,若设为True,队列满时会阻塞当前线程,若设为False,队列满时会抛出queue.Full异常;timeout参数代表超时时长,若timeout设为None,会无限期等待至队列中空出一个元素单元,若timeout设为正数,会阻塞等待指定时长后,抛出queue.Full异常。需要注意的是,若block参数设为False,会忽略timeout参数
put_nowait(item) 立即向队列中存入一个元素,相当于put(item, False)
get(block=True, timeout=None) 移除并返回队头的第一个元素。该方法中共包含2个参数,block参数代表是否阻塞队列,若设为True,队列空时会阻塞当前线程,若设为False,队列空时会抛出queue.Empty异常;timeout参数代表超时时长,若timeout设为None,会无限期等待至队列中插入一个元素,若timeout设为正数,会阻塞等待指定时长后,抛出queue.Empty异常。
get_nowait() 立即从队列中取出一个元素,相当于get(False)

为了能够让大家更好地理解,下面通过一个示例来演示如何让主线程和多个子线程协调合作,主线程往队列中插入完数据之后,它等子线程取出所有的数据之后结束执行,具体代码如下:

import threading
from queue import Queue
from threading import Thread, Lock
import time
class MyThread (Thread):
  def __init__(self, threadID, name, q):
     super().__init__()
     self.threadID = threadID
     self.name = name
     self.q = q
  def run(self):
     print(self.name + "开始 ")
     process_data(self.name, self.q)
     print(self.name + "结束 ")
def process_data(threadName, q):
  while not exit_flag:
     queueLock.acquire()
     if not workQueue.empty():
       data = q.get()
       queueLock.release()
       print("%s 取出元素 %s" % (threadName, data))
     else:
       queueLock.release()
     time.sleep(1)
exit_flag = 0  # 线程退出标记
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = Lock()
workQueue = Queue(10)
threads = []
threadID = 1
# 创建新线程
for tName in threadList:
  thread = MyThread(threadID, tName, workQueue)
  thread.start()
  threads.append(thread)
  threadID += 1
# 填充队列
queueLock.acquire()
for word in nameList:
  workQueue.put(word)
  print("%s 存入元素 %s" % (threading.currentThread().name, word))
queueLock.release()
# 等待队列清空
while not workQueue.empty():
  pass
# 通知线程是时候退出
exit_flag = 1
# 等待所有线程完成
for t in threads:
  t.join()
print("主线程结束")

运行代码,结果如下所示:

Thread-1开始 
Thread-2开始 
Thread-3开始 
MainThread 存入元素 One
MainThread 存入元素 Two
MainThread 存入元素 Three
MainThread 存入元素 Four
MainThread 存入元素 Five
Thread-3 取出元素 One
Thread-1 取出元素 Two
Thread-2 取出元素 Three
Thread-3 取出元素 Four
Thread-2 取出元素 Five
Thread-2结束 
Thread-3结束 
Thread-1结束 
主线程结束
点击此处
隐藏目录