当我使用dictionary.get()
函数时,是否锁定整个字典?我正在开发一个多进程和多线程程序。字典用作状态表以跟踪数据。我必须对字典施加大小限制,所以每当达到限制时,我必须根据时间戳在表上进行垃圾收集。当垃圾收集迭代整个表时,当前实现将延迟添加操作。
我将拥有2个或更多线程,一个用于添加数据,另一个用于垃圾回收。在我的程序中,性能是 critical 来处理流数据。我的程序正在接收流数据,每当收到消息时,它必须在状态表中查找它,然后添加记录,如果它首先不存在,或者复制某些信息然后沿管道发送
我曾考虑使用multiprocessing
同时进行搜索和添加操作,但是如果我使用了进程,我必须为每个进程制作状态表的副本,在这种情况下,同步的性能开销太高了。我还读到multiprocessing.manager.dict()
也锁定了每个CRUD操作的访问权限。我无法节省开销,因此我目前的方法是使用线程。
所以我的问题是当一个线程在表上执行.get()
,del dict['key']
操作时,是否会阻止另一个插入线程访问它?
注意:我已经阅读了大多数 SO 的python词典相关帖子,但我似乎无法找到答案。大多数人只回答这一点,即使python字典操作是原子的,使用 Lock 进行插入/更新也更安全。我正在处理大量的流数据,所以每次锁定对我来说并不理想。请告知是否有更好的方法。
答案 0 :(得分:4)
如果散列或比较字典中的键的过程可以调用任意Python代码(基本上,如果键不是所有用C实现的Python内置类型,例如str
,{{ 1}},int
等等,然后是的,有可能发生竞争条件,其中在解决桶冲突时(在相等测试期间)释放GIL,并且另一个线程可以跳跃并导致被比较的对象从float
消失。他们试图确保它实际上并没有使解释器崩溃,但它在过去一直是错误的来源。
如果有可能(或者你是非CPython解释器,没有GIL提供这样的基本保证),那么你应该使用锁来协调访问。在CPython上,只要您使用现代Python 3,成本就会相当低;锁定上的争用应该相当低,因为GIL确保只有一个线程实际上同时运行;大部分时间你的锁应该是无竞争的(因为争用在GIL上),所以使用它的增量成本应该相当小。
注意:您可以考虑使用dict
来简化限制表格大小的过程。使用collections.OrderedDict
,您可以将大小限制实现为严格的LRU(最近最少使用)系统,方法是将表添加到表中:
OrderedDict
用法完成:
with lock:
try:
try:
odict.move_to_end(key) # If key already existed, make sure it's "renewed"
finally:
odict[key] = value # set new value whether or not key already existed
except KeyError:
# move_to_end raising key error means newly added key, so we might
# have grown larger than limit
if len(odict) > maxsize:
odict.popitem(False) # Pops oldest item
这确实需要一个锁,但它也会减少垃圾收集的工作量,当垃圾收集量过大时,检查每个键" (with lock:
# move_to_end optional; if using key means it should live longer, then do it
# if only setting key should refresh it, omit move_to_end
odict.move_to_end(key)
return odict[key]
工作)到#34;关闭最旧的项目而不查看任何其他内容" (O(n)
工作)。
答案 1 :(得分:0)
锁用于避免竞争条件,因此没有两个线程可以同时更改dict,因此建议您使用锁定,否则可能会进入竞争状态导致程序失败。可以使用互斥锁来处理2个线程。