@@ -171,15 +171,24 @@ def _create_and_install_waiters(fs, return_when):
171171 return waiter
172172
173173
174- def _yield_and_decref (fs , ref_collect ):
174+ def _yield_finished_futures (fs , waiter , ref_collect ):
175175 """
176- Iterate on the list *fs*, yielding objects one by one in reverse order.
177- Before yielding an object, it is removed from each set in
178- the collection of sets *ref_collect*.
176+ Iterate on the list *fs*, yielding finished futures one by one in
177+ reverse order.
178+ Before yielding a future, *waiter* is removed from its waiters
179+ and the future is removed from each set in the collection of sets
180+ *ref_collect*.
181+
182+ The aim of this function is to avoid keeping stale references after
183+ the future is yielded and before the iterator resumes.
179184 """
180185 while fs :
186+ f = fs [- 1 ]
181187 for futures_set in ref_collect :
182- futures_set .remove (fs [- 1 ])
188+ futures_set .remove (f )
189+ with f ._condition :
190+ f ._waiters .remove (waiter )
191+ del f
183192 # Careful not to keep a reference to the popped value
184193 yield fs .pop ()
185194
@@ -216,7 +225,8 @@ def as_completed(fs, timeout=None):
216225 waiter = _create_and_install_waiters (fs , _AS_COMPLETED )
217226 finished = list (finished )
218227 try :
219- yield from _yield_and_decref (finished , ref_collect = (fs ,))
228+ yield from _yield_finished_futures (finished , waiter ,
229+ ref_collect = (fs ,))
220230
221231 while pending :
222232 if timeout is None :
@@ -237,9 +247,11 @@ def as_completed(fs, timeout=None):
237247
238248 # reverse to keep finishing order
239249 finished .reverse ()
240- yield from _yield_and_decref (finished , ref_collect = (fs , pending ))
250+ yield from _yield_finished_futures (finished , waiter ,
251+ ref_collect = (fs , pending ))
241252
242253 finally :
254+ # Remove waiter from unfinished futures
243255 for f in fs :
244256 with f ._condition :
245257 f ._waiters .remove (waiter )
0 commit comments