Python 字典中的线程安全

我有一个有字典的班级

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之前必须使用锁?

117381 次浏览

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

你的代码应该是安全的。记住: 这里的一个锁几乎不会增加开销,而且会给你带来内心的平静。

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

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

这在 Python 变量赋值是原子的吗?上有进一步的详细解释

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

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

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


我同意这一点: 在 CPython 中已经有了 GIL,所以使用 Lock 对性能的影响可以忽略不计。当某天 CPython 实现细节发生变化时,在复杂的代码库中花费的时间将会更加昂贵。

当使用 python 的内置 dict 时,set 和 get 是原子的(因为 但是,这似乎是一种不好的做法,因为诸如. item 之类的操作并不是原子的。

如果多个线程正在处理相同的 dict 键,则 Note-get-add-set 操作不是线程安全的。

Dict ()不是线程安全的。

import threading


dic = dict()


def producer():
for i in range(1000000):
dic[i] = i


def consumer():
for key, value in dic.items():
print(key, value)


th1 = threading.Thread(target=producer)
th2 = threading.Thread(target=consumer)
th1.start()
th2.start()
th1.join()
th2.join()

RuntimeError: 在迭代过程中字典的大小发生了变化