我想知道dict.update()是否是python线程安全的。我已经阅读了相关的问题,但是没有一个能完全解决我的问题。
我的问题非常具体和简单。例如,我已经有本地字典d2
。我只需要使用d
更新全局字典d2
,如下所示。 d
开始为空,并充满了不同的线程。每个线程中的d2
可能与d
有重叠的条目(不要紧)。线程安全吗?
import dis
def f(d):
d2 = {1:2, 3:4}
d.update(d2)
print(dis.dis(f))
字节码如下:
10 0 LOAD_CONST 1 (2)
2 LOAD_CONST 2 (4)
4 LOAD_CONST 3 ((1, 3))
6 BUILD_CONST_KEY_MAP 2
8 STORE_FAST 1 (d2)
11 10 LOAD_FAST 0 (d)
12 LOAD_ATTR 0 (update)
14 LOAD_FAST 1 (d2)
16 CALL_FUNCTION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
看起来16 CALL_FUNCTION
是更新字典的原子函数。所以应该是线程安全的吗?
答案 0 :(得分:8)
如果键是内置的可哈希类型的组合,通常为“是”,则.update()
是线程安全的。特别是,对于您使用整数键的示例,是的。
但是一般,不。在字典中查找键 可以在用户提供的__hash__()
和__eq__()
方法中调用任意用户定义的Python代码,这些方法可以执行任何操作-包括执行其自己在涉及的字典上的变异。该实现调用Python代码后,其他线程也可以运行,包括 也可能正在突变d1
和/或d2
的线程。
对于内置的可哈希类型(int,字符串,浮点数,元组等)来说,这不是潜在的问题-它们的实现可用于计算哈希码并确定相等性是纯粹的功能(确定性且无副作用),并且不会释放GIL(全局解释器锁)。
关于CPython(Python的C实现)。在其他实现下,答案可能会有所不同! 《语言参考手册》对此保持沉默。
答案 1 :(得分:0)
如果可以使用外部库,则可以研究locked-dict。
摘自自述文件:
Dict允许上下文管理的线程安全且可变的迭代 通过锁。
例如,来自他们的tests:
pip install locked-dict
import locked_dict
expected = 0
d = locked_dict.LockedDict()
assert len(d) == expected
assert bool(d) is False
assert d is not True
assert hasattr(d, '_lock')
empty_d = {}
assert d == empty_d
plain_old_d = {999: 'plain old dict', 12345: 54321}
assert d != plain_old_d
with d as m:
assert len(m) == expected
assert bool(m) is False
assert m is not True
assert hasattr(m, '_lock')
assert m != plain_old_d
assert m == empty_d
m[0] = ['foo']
expected += 1
assert len(m) == expected
assert bool(m) is True
assert m is not False
assert m != plain_old_d
assert m != empty_d
m.clear()
expected -= 1
assert len(m) == expected
assert bool(m) is False
assert m is not True
assert m != plain_old_d
assert m == empty_d
尽管该库可能与您的用例无关,但请不要让它使用3年。