Python字典中的线程安全


103

我有一堂课,有一本字典

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

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

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

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

这样安全吗,还是在致电之前必须使用锁addOrder


2
当每个线程无论如何都写入不同的键时,怎么会有问题。
Jochen Ritzel 2011年

63
@Jochen:取决于如何执行命令,很多地方可能出错。这是一个非常合理的问题。
Ned Batchelder

Answers:


94

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

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

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


6
这是effbot.org 实施锁的
滚刀

1
应该考虑单个操作与组合操作,例如get-add-set
andy 2014年

5
问题是,当我经常读/写该命令时,那种内心的平静会让我付出很多代价。
Shihab Shahriar Khan

2
“这里的锁几乎不会增加任何开销”:为什么呢?
最多

31

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

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


24
这不是Python的功能,而是cpython的功能
phihag 2011年

8
没错,但是据我了解,即使不使用GIL,Jython和IronPython中的内置程序也是线程安全的(并且,如果出现这种情况,也应取消GIL)。我假设由于他没有指定他使用的解释器,所以他在CPython中的意思是。

1

9

Google的风格指南建议不要依赖dict原子性

在以下位置进一步详细解释:Python变量赋值是原子的吗?

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

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.