这个Python中的双端队列是线程安全的吗?

28 投票
3 回答
33465 浏览
提问于 2025-04-17 08:36

我不太确定下面这个双端队列(deque)是否是线程安全的。
简单来说,我创建了一个类,这个类里面有一个双端队列,每隔1秒在一个新线程中显示它的内容(这样打印的时候不会暂停主程序)。
这个双端队列是由主线程填充的,所以基本上是有可能发生冲突的。
但是,填充双端队列是通过类的方法来完成的,所以实际上是从实例内部访问的,也就是在同一个线程中。
下面是简化后的代码:

import threading
import time
from collections import deque

class MyQueue(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.q = deque()
        self.start()

    def run(self):
        # pop out queue items every 1 sec
        # (please ignore empty deque for now)
        while True:
            print self.q.popleft()
            time.sleep(1)

    def add_to_q(self, val):
        # this function is called from outside
        self.q.append(val)

# main
# fill the queue with values
qu = MyQueue()
for i in range(1:100):
    qu.add_to_q(i)

所以,尽管添加和移除队列中的项目是在实例内部进行的,但由于添加函数是从实例外部调用的,这样是否会有风险呢?

补充说明:
因为我需要修改双端队列中的项目,所以我必须使用双端队列。我所做的就是:先旋转到指定的项目,弹出它,修改后再放回去,然后再旋转回原来的位置。
除非我找到在队列中修改项目的方法,否则我只能继续使用双端队列。

3 个回答

10

这里有一个关于Python的票据,提到deque(双端队列)在多线程中的安全性问题,链接在这里:https://bugs.python.org/issue15329

标题是“明确哪些deque方法是线程安全的”,总结一下就是:

在CPython中,deque的append()、appendleft()、pop()、popleft()和len(d)这些操作是线程安全的。append方法在最后会有一个DECREF(这是在设置了最大长度的情况下),但这个操作是在所有结构更新完成后进行的,所以可以把这些操作看作是原子的,也就是说它们不会被打断。

不过,如果你不太确定,并且更看重可靠性而不是性能的话,可以在print self.q.popleft()self.q.append(val)这两行代码上加个锁;这样会更安全哦!

28

这里是Deque的作者。

我觉得MyQueue()这个类看起来是正确的(至少在线程安全的问题上是这样)。

append()popleft()这两个方法都是原子操作,也就是说它们在执行时不会被打断。

不过,代码确实需要用到EAFP的逻辑来处理输入为空的情况:

def run(self):
    while True:
        try:
            print self.q.popleft()
        except IndexError:
            pass
        time.sleep(1)
31

双端队列(Deque)是线程安全的,这意味着在不同的线程中同时进行添加和删除操作时,它能保证数据的安全性。你可以在这个链接里查看详细信息:http://docs.python.org/library/collections.html#deque-objects。不过在下面的文档中,只提到append()和popleft()这两个操作是线程安全的,其他的操作没有特别说明。

此外,队列(Queue)本身也有一个线程安全的实现。所以如果你没有特别奇怪的需求,建议你使用这个线程安全的队列。

撰写回答