bpo-20369: concurrent.futures.wait() now deduplicates futures given a… · python/cpython@7d7817c (original) (raw)

4 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -444,7 +444,8 @@ Module Functions
444 444 .. function:: wait(fs, timeout=None, return_when=ALL_COMPLETED)
445 445
446 446 Wait for the :class:`Future` instances (possibly created by different
447 -:class:`Executor` instances) given by *fs* to complete. Returns a named
447 +:class:`Executor` instances) given by *fs* to complete. Duplicate futures
448 + given to *fs* are removed and will be returned only once. Returns a named
448 449 2-tuple of sets. The first set, named ``done``, contains the futures that
449 450 completed (finished or cancelled futures) before the wait completed. The
450 451 second set, named ``not_done``, contains the futures that did not complete
Original file line number Diff line number Diff line change
@@ -282,13 +282,14 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
282 282 A named 2-tuple of sets. The first set, named 'done', contains the
283 283 futures that completed (is finished or cancelled) before the wait
284 284 completed. The second set, named 'not_done', contains uncompleted
285 - futures.
285 + futures. Duplicate futures given to *fs* are removed and will be
286 + returned only once.
286 287 """
288 +fs = set(fs)
287 289 with _AcquireFutures(fs):
288 -done = set(f for f in fs
289 -if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
290 -not_done = set(fs) - done
291 -
290 +done = {f for f in fs
291 +if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]}
292 +not_done = fs - done
292 293 if (return_when == FIRST_COMPLETED) and done:
293 294 return DoneAndNotDoneFutures(done, not_done)
294 295 elif (return_when == FIRST_EXCEPTION) and done:
@@ -307,7 +308,7 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
307 308 f._waiters.remove(waiter)
308 309
309 310 done.update(waiter.finished_futures)
310 -return DoneAndNotDoneFutures(done, set(fs) - done)
311 +return DoneAndNotDoneFutures(done, fs - done)
311 312
312 313 class Future(object):
313 314 """Represents the result of an asynchronous computation."""
Original file line number Diff line number Diff line change
@@ -578,6 +578,14 @@ def test_shutdown_no_wait(self):
578 578
579 579
580 580 class WaitTests:
581 +def test_20369(self):
582 +# See https://bugs.python.org/issue20369
583 +future = self.executor.submit(time.sleep, 1.5)
584 +done, not_done = futures.wait([future, future],
585 +return_when=futures.ALL_COMPLETED)
586 +self.assertEqual({future}, done)
587 +self.assertEqual(set(), not_done)
588 +
581 589
582 590 def test_first_completed(self):
583 591 future1 = self.executor.submit(mul, 21, 2)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 +:func:`concurrent.futures.wait` no longer blocks forever when given duplicate Futures. Patch by Kumar Aditya.