线程安全的排序集合

4 投票
5 回答
4416 浏览
提问于 2025-04-17 04:58

在Python中有没有线程安全的排序集合的实现呢?
Python的文档提到过bisect模块,还有一个叫SortedCollection的东西,但我不确定它是否线程安全(它是吗?)
如果没有这样的实现,那该怎么去实现呢?

5 个回答

1

Python和Java不一样:如果一个类在文档中没有说明它的线程行为,那就可以安全地认为它不是线程安全的。

Python在设计时并没有考虑到多线程。即使到现在,多线程也算是个“二等公民”,因为在任何时候只有一个线程在活动(这并不防止大多数数据竞争问题)。这个机制叫做全局解释器锁(GIL)。

如果一个类或数据结构没有为并发设计,你就需要通过一个外部锁来保护对它的访问。

2

collections.OrderedDict 类在更新时不是线程安全的。这意味着你可以同时读取数据,但在写入数据时需要使用锁。想了解如何在 OrderedDict 中使用锁,可以查看 functools.lru_cache() 的源代码示例。

4

从代码来看,它似乎不是线程安全的。如果多个线程要使用它,访问它的应用代码应该加上信号量锁来保护。

如果你想让SortedCollection类变得线程安全,可以写一个装饰器函数来实现。

它的样子可能是这样的:

SortedCollection:

def __init__(self):
    self.mysemaphore = threading.Semaphore()

def guard(func):
    def guarded(*args, **kwds):
        self.mysemaphore.acquire()
        try:
            return func(*args, **kwds)
        finally:
            self.mysemaphore.release()

return guarded

# edit the class, applying the decorator to its methods.
@guard
def unsafeFunc(self, a, b, c):
    ''' do work here'''

编辑

不要误以为一个线程安全的数据结构就能让你的应用代码也变得线程安全。如果你在SortedCollection上执行多个操作,这些操作都需要加锁来保护。

即使SortedCollection是线程安全的,下面的代码也不是:

slist.insert(1)
slist.insert(2)

可能在这两条语句之间,另一个线程会插入一个项目。你需要在你的应用代码中加锁。如果你在应用代码中加上这个,就不需要修改SortedCollection来让它变得线程安全。

semaphore2.acquire()

try:
    slist.insert(1)
    slist.insert(2)
finally:
    semaphore2.release()

撰写回答