queue模块

2020年1月28日 / 14次阅读 / Last Modified 2020年1月28日
多线程

python标准库中有一个queue模块,此模块提供了创建和使用队列的底层封装,而且是线程安全的!queue模块提供FIFO队列,LIFO队列,以及优先级队列。从3.7开始,还提供了一个SimpleQueue对象。queue模块的官方链接:https://docs.python.org/3/library/queue.html

值得注意的是,queue模块中的不同类型的队列,他们对应的成员函数基本一致!

>>> import queue
>>> q = queue.Queue()
>>> q.qsize()
0
>>> q.put(1)
>>> q.qsize()
1
>>> q.get()
1
>>> q.qsize()
0
>>> q.empty()
True
>>> for i in range(10): q.put(i)
...
>>> q.qsize()
10
>>> for i in range(10): q.get()
...
0
1
2
3
4
5
6
7
8
9
>>> q.qsize()
0

import queue后,创建一个不限长度的FIFO队列q,qsize可以得到队列的当前长度,put进行入队操作,get进行出队操作,严格按照FIFO的规则进行。

以上代码需要注意的是,qsize得到队列当前长度,但是在多线程场景下,qsize返回的结果不能作为put或get是否会block的依据。

put和get函数可能被阻塞,当队列达到最大值时的put,以及队列为空时的get,这两个函数都会被阻塞。在单线程场景下,也会阻塞,此时的阻塞就是bug。下面的代码会阻塞,请同学自己测试:

>>> import queue
>>> q = queue.Queue(1)
>>> q.put(1)
>>> q.qsize()
1
>>> q.put(2)  # blocking
>>> import queue
>>> q = queue.Queue()
>>> q.qsize()
0
>>> q.get()  # blocking

不想阻塞也可以:

>>> import queue
>>> q = queue.Queue()
>>> q.get_nowait()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\queue.
py", line 198, in get_nowait
    return self.get(block=False)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\queue.
py", line 167, in get
    raise Empty
_queue.Empty

get_nowait等同于get(False),同样也有put_nowait函数(如果不能成功,抛出Full异常)。get和put函数还可以设置一个timeout参数,即阻塞的最大时长。

在多线程场景下,task_done和join函数还挺有用的。threading.Thread提供的join函数,表示等待线程执行完成。queue模块气筒的join函数,表示等待queue中所有的task都处理完成,put函数增加一个task,get函数取出一个task。用get函数取出task,处理完后,一定要调用task_done函数,来表示此task已经done。task这个概念,是queue模块抽象出来的。

python官方给出了一个使用task_done和join的例子:

def worker():
    while True:
        item = q.get()
        if item is None:
            break
        do_work(item)
        q.task_done()

q = queue.Queue()
threads = []
for i in range(num_worker_threads):
    t = threading.Thread(target=worker)
    t.start()
    threads.append(t)

for item in source():  
    q.put(item)

# block until all tasks are done
q.join()

# stop workers
for i in range(num_worker_threads):
    q.put(None)
for t in threads:
    t.join()

source是没有定义的,只是示例而已;可以put(None),在以上代码中,相当于给出线程的结束信号。有一个词,叫做queue的task tracking功能

python3.7开始提供了一个SimpleQueue的类,顾名思义,这个类就是没有长度限制的FIFO Queue,而且也没有task tracking的功能!

-- EOF --

本文链接:https://www.pynote.net/archives/1751

留言区

《queue模块》有1条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    multiprocessing模块中有一个与此几乎一样的Queue类,可用于对进程间的信息传递。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top