Python字典中的线程安全

时间:2011-08-05 08:16:37

标签: python multithreading dictionary thread-safety

我有一个持有字典的课程

class OrderBook:
    orders = {'Restaurant1': None,
              'Restaurant2': None,
              'Restaurant3': None,
              'Restaurant4': None}

    @staticmethod
    def addOrder(restaurant_name, orders):
        OrderBook.orders[restaurant_name] = orders

我正在运行调用方法OrderBook.addOrder的4个线程(每个餐厅一个)。这是每个线程运行的函数:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

这是安全的,还是在调用addOrder之前我必须使用锁?

4 个答案:

答案 0 :(得分:74)

Python的内置结构对于单个操作是线程安全的,但有时很难看到语句真正成为多个操作的位置。

您的代码应该是安全的。请记住:这里的锁定几乎不会增加任何开销,让您高枕无忧。

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm有更多详情。

答案 1 :(得分:25)

是的,内置类型本质上是线程安全的: http://docs.python.org/glossary.html#term-global-interpreter-lock

  

这通过使对象模型(包括关键的内置类型,如dict )隐式安全地防止并发访问,简化了CPython实现。

答案 2 :(得分:1)

值得注意的是,Google的风格指南建议不要依赖于dict原子性,正如我在Is Python variable assignment atomic?

中进一步详细解释的那样
  

不要依赖内置类型的原子性。

     

虽然Python的内置数据类型(例如字典)似乎具有原子操作,但在某些极端情况下它们不是原子操作(例如,如果__hash____eq__被实现为Python方法)和不应该依赖它们的原子性。您也不应该依赖于原子变量赋值(因为这又取决于字典)。

     

使用Queue模块的Queue数据类型作为在线程之间通信数据的首选方法。否则,请使用线程模块及其锁定原语。了解如何正确使用条件变量,以便您可以使用threading.Condition而不是使用较低级别的锁。

我同意这一观点:CPython中已经存在GIL,因此使用Lock的性能影响可以忽略不计。当这些CPython实现细节有一天改变时,花在复杂代码库中的错误查找所花费的时间将大大增加。

答案 3 :(得分:0)

当使用 python 的内置 dict 时,set 和 get 是原子的(因为 cpython 的 GIL)。然而,这似乎是不好的做法,因为 .items 之类的操作不是原子的。

注意 - 如果多个线程处理相同的字典键,get-add-set 操作不是线程安全的。