详解Python中 queue.queue 和 collections.deque 的区别

  • Post category:Python

Python中的queue.queue和collections.deque都提供了队列数据结构的实现,但它们之间有些许的不同。

queue.queue和collections.deque的主要区别

queue.queue和collections.deque的主要区别包括以下几点:

实现机制

queue.queue是Python标准库提供的声明式队列(FIFO)结构,它是线程安全的。queue.Queue底层使用线程锁来保证安全访问。它里面含有的成员函数,如put, get,task_done, join都是线程安全的。

collections.deque也是Python标准库中的一个数据结构,它是非线程安全的,不提供线程安全的保障,但提供了既可以在队列头部和队列尾部插入与删除的双端队列。deque底层使用的是双向链表,插入、删除的时间复杂度为O(1),相对于queue.Queue速度更快。

应用场景

queue.Queue一般用于多线程的场景,如果只是单线程的场景,建议使用deque,前者在多线程环境下使用相对安全些,能够保证“线出、线进”;后者在性能上相对高效一些,但不适用于多线程环境,尤其不适用于多个线程同时put和get一个队列,可能会出现混乱。

使用方式

queue.Queue使用常见如下:

import queue

q = queue.Queue()

q.put("value")
q.get()
q.task_done()
q.join()

collections.deque使用常见如下:

import collections

dq = collections.deque()

dq.append("value")
dq.popleft()

示例说明

示例1

以下示例说明queue.Queue实现线程安全的过程

import threading
import queue

def consumer(q):
    while True:
        if not q.empty():
            print("consume value:{}".format(q.get()))
            q.task_done()
        else:
            break

q = queue.Queue()
for i in range(10):
    q.put(i)

threads = []
for i in range(5):
    t = threading.Thread(target=consumer, args=(q,))
    threads.append(t)
    t.start()

q.join()
for t in threads:
    t.join()

在上述示例中,创建了一个queue.Queue实例,将10个数字放入队列中,创建5个消费者线程,从队列中依次取出数字进行消费,直到队列为空。queue.Queue实现线程安全的方式是采用线程锁,使用get(), put(), task_done(), join()等成员函数时都是线程安全的。

示例2

以下示例说明collections.deque实现双向队列的过程:

import collections

dq = collections.deque()

dq.append(1)
dq.appendleft(2)
dq.append("end")

print(dq)
print(dq.pop())
print(dq.popleft())
print(dq)

在上述示例中,创建了一个collections.deque实例,使用append()和appendleft()函数在队列尾部和队列头部插入元素,使用pop()和popleft()函数在队列尾部和队列头部删除元素。deque在使用上更灵活,可以在队列尾部和队列头部插入与删除数据。