8000 bpo-20369: concurrent.futures.wait() now deduplicates futures given a… · python/cpython@7d7817c · GitHub
[go: up one dir, main page]

Skip to content

Commit 7d7817c

Browse files
bpo-20369: concurrent.futures.wait() now deduplicates futures given a… (GH-30168)
* bpo-20369: concurrent.futures.wait() now deduplicates futures given as arg. * 📜🤖 Added by blurb_it. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent b949845 commit 7d7817c

File tree

4 files changed

+18
-7
lines changed

4 files changed

+18
-7
lines changed

Doc/library/concurrent.futures.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,8 @@ Module Functions
444444
.. function:: wait(fs, timeout=None, return_when=ALL_COMPLETED)
445445

446446
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
448449
2-tuple of sets. The first set, named ``done``, contains the futures that
449450
completed (finished or cancelled futures) before the wait completed. The
450451
second set, named ``not_done``, contains the futures that did not complete

Lib/concurrent/futures/_base.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,14 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
282282
A named 2-tuple of sets. The first set, named 'done', contains the
283283
futures that completed (is finished or cancelled) before the wait
284284
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.
286287
"""
288+
fs = set(fs)
287289
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
292293
if (return_when == FIRST_COMPLETED) and done:
293294
return DoneAndNotDoneFutures(done, not_done)
294295
elif (return_when == FIRST_EXCEPTION) and done:
@@ -307,7 +308,7 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
307308
f._waiters.remove(waiter)
308309

309310
done.update(waiter.finished_futures)
310-
return DoneAndNotDoneFutures(done, set(fs) - done)
311+
return DoneAndNotDoneFutures(done, fs - done)
311312

312313
class Future(object):
313314
"""Represents the result of an asynchronous computation."""

Lib/test/test_concurrent_futures.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ def test_shutdown_no_wait(self):
578578

579579

580580
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+
581589

582590
def test_first_completed(self):
583591
future1 = self.executor.submit(mul, 21, 2)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`concurrent.futures.wait` no longer blocks forever when given duplicate Futures. Patch by Kumar Aditya.

0 commit comments

Comments
 (0)
0