Reputation: 860
I have a Python application where thread1 calls an API to see 'what reports are ready to download' and sends that report_id
to thread2 which 'downloads/processes those reports. I am trying to determine what happens if thread1 is adding items to the dict if thread2 is iterating over it. Right now I do a copy before working in thread2
Two questions
Can I iterate over a changing dictionary? I currently a) make a copy of dict before I iterate, b) iterate over a copy of the dict, c) for items that are 'processed' by the loop on the copy of the dict I delete the key from the 'original' dict so on the next loop it doesn't reprocess the same item
If I can't iterate over a changing dict do I need to use a lock to make a copy like I am doing below. Is that the right way to do it?
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]
Upvotes: 0
Views: 52
Reputation: 2614
>>> 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
del
statements below) must acquire the lock as well, otherwise, it may delete items at any time while your thread is creating the deep copy, potentially causing the same trouble, particularly if the dictionary size is large enough that the deep copy could be interrupted by the deletion process.Upvotes: 1