dict.update()线程安全吗?

问题描述 投票:2回答:2

我想知道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是更新字典的原子函数。那么它应该是线程安全的吗?

python multithreading dictionary
2个回答
8
投票

如果键是内置可清洗类型的组合,通常为“是”,.update()是线程安全的。特别是对于带有整数键的示例,是的。

但总的来说,没有。查找dict中的键可以在用户提供的__hash__()__eq__()方法中调用任意用户定义的Python代码,这些方法可以做任何事情 - 包括在所涉及的dicts上执行自己的突变。一旦实现调用Python代码,其他线程也可以运行,包括可能正在改变d1和/或d2的线程。

这不是内置可混合类型(整数,字符串,浮点数,元组......)的潜在问题 - 它们计算哈希码并确定相等的实现纯粹是功能性的(确定性且没有副作用)并且不释放GIL (全球翻译锁)。

这就是CPython(Python的C实现)。在其他实施中,答案可能有所不同!语言参考手册对此保持沉默。


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岁,虽然它可能仍然与您的用例相关

© www.soinside.com 2019 - 2024. All rights reserved.