我想知道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
是更新字典的原子函数。那么它应该是线程安全的吗?
如果键是内置可清洗类型的组合,通常为“是”,.update()
是线程安全的。特别是对于带有整数键的示例,是的。
但总的来说,没有。查找dict中的键可以在用户提供的__hash__()
和__eq__()
方法中调用任意用户定义的Python代码,这些方法可以做任何事情 - 包括在所涉及的dicts上执行自己的突变。一旦实现调用Python代码,其他线程也可以运行,包括可能正在改变d1
和/或d2
的线程。
这不是内置可混合类型(整数,字符串,浮点数,元组......)的潜在问题 - 它们计算哈希码并确定相等的实现纯粹是功能性的(确定性且没有副作用)并且不释放GIL (全球翻译锁)。
这就是CPython(Python的C实现)。在其他实施中,答案可能有所不同!语言参考手册对此保持沉默。
如果您使用外部库,可以查看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岁,虽然它可能仍然与您的用例相关