【问题标题】:Thread safe copying of a deque without blocking append线程安全复制双端队列而不阻塞追加
【发布时间】:2019-11-01 06:10:24
【问题描述】:

我正在尝试在 python 中创建一个循环缓冲区。 我最好的实现是使用固定长度的deque
(基本实现)

class RingBuffer(object):
    def __init__(self, size):
        self.mutex = Lock()
        self.deque = collections.deque(maxlen=size)

    def push_elem(self, element):
        copy.deepcopy(element)
        with self.mutex:
            self.deque.append(element)

    def get_data(self, event, callback=None):
        with self.mutex:
            return copy.deepcopy(list(self.deque))


    def get_elem(self):
        if self.deque:
            with self.mutex:
                return cp.deepcopy(self.deque[-1])
        return None

我知道从两侧追加和删除元素是线程安全的,但我还需要能够复制 N 个元素。这就是我使用这个互斥锁的原因。
问题是我不想在其他线程复制缓冲区中的数据时阻止新元素的插入。
有没有办法在没有互斥锁的情况下实现这种行为?

【问题讨论】:

  • 你问的是无锁编程吗?无论如何,这在 Python 中非常复杂且毫无意义(Python 中至少有一个互斥锁是不可避免的:GIL)。或者您是否希望读取器和插入器能够同时运行(换句话说,您想要短暂的互斥锁)?
  • @freakish 我不想在复制缓冲区数据时阻止附加操作。例如:双端队列包含 30 个元素(从 0 到 29 的整数)我想从右边复制 20 个(9 到 29)。虽然发生这种情况,但我希望仍然能够将新元素从不同的线程推送到缓冲区,而无需等待互斥体
  • 对,所以你这里的操作是CRUD(创建读取更新删除),可能只有CRD。所以你现在的“锁定一切”策略是一个悲观的concurrency control method。还有其他的,例如MVCC 在 PostgreSQL 中实现。无论如何,这是一个巨大的话题,这些算法并不容易。不要指望它会通过一些魔术来实现这一点。您很可能还需要更改数据结构。

标签: python multithreading deque


【解决方案1】:

在 CPython 中,这个副本是原子的(一旦它开始运行):

s = list(islice(some_deque, 20))

列表构建、使用 itertools 切片和 deque 迭代都是用 C 实现的,没有纯 python 回调。此外,复制操作不会导致任何 DECREF 降为零,从而消除了非原子行为的另一个来源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 2017-09-13
    • 2019-02-12
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-06-26
    相关资源
    最近更新 更多