当另一个线程将数据添加到字典时,您可以迭代字典吗?

时间:2021-02-25 17:30:22

标签: python dictionary

我有一个 Python 应用程序,其中 thread1 调用 API 以查看“准备下载哪些报告”并将该 report_id 发送到“下载/处理这些报告”的 thread2。我试图确定如果 thread1 将项目添加到 dict 如果 thread2 正在迭代它会发生什么。现在我在使用 thread2 之前先复制一份

两个问题

  1. 我可以遍历不断变化的字典吗?我目前a)在迭代之前制作dict的副本,b)迭代dict的副本,c)对于由dict副本上的循环“处理”的项目我从“原始”中删除密钥dict 所以在下一个循环中它不会重新处理相同的项目

  2. 如果我不能迭代一个不断变化的字典,我是否需要使用锁来制作一个副本,就像我在下面做的那样。这是正确的做法吗?

lock = threading.Lock()
while True:

        with lock:  #copy dict to prevent contenion
            reports_to_call_copy = self.reports_to_call.copy()

        for line in reports_to_call_copy:
              #do stuff and delete items from original dict so on next loop it doesn't process twice. 


        is_killed = self._kill.wait(180)
        if is_killed:
            print("Killing - Request Report")
            break
              del self.reports_to_call[user, report_name]

1 个答案:

答案 0 :(得分:1)

  1. 不,不可能迭代一个不断变化的字典,即使是在同一个线程中改变。最简单的可重现示例:
>>> d = dict()
>>> d['a'] = 10
>>> for k, v in d.items():
...     del d['a']
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
  1. 任何操作字典的代码(例如下面的 del 语句)也必须获取锁,否则,它可能会在您的线程创建深拷贝,可能会导致同样的问题,特别是如果字典大小足够大,深拷贝可能会被删除过程中断。
相关问题