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

Skip to content

Commit 9a9061d

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> (cherry picked from commit 7d7817c) Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
1 parent 8f082e2 commit 9a9061d

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
@@ -435,7 +435,8 @@ Module Functions
435435
.. function:: wait(fs, timeout=None, return_when=ALL_COMPLETED)
436436

437437
Wait for the :class:`Future` instances (possibly created by different
438-
:class:`Executor` instances) given by *fs* to complete. Returns a named
438+
:class:`Executor` instances) given by *fs* to complete. Duplicate futures
439+
given to *fs* are removed and will be returned only once. Returns a named
439440
2-tuple of sets. The first set, named ``done``, contains the futures that
440441
completed (finished or cancelled futures) before the wait completed. The
441442
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
@@ -284,13 +284,14 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
284284
A named 2-tuple of sets. The first set, named 'done', contains the
285285
futures that completed (is finished or cancelled) before the wait
286286
completed. The second set, named 'not_done', contains uncompleted
287-
futures.
287+
futures. Duplicate futures given to *fs* are removed and will be
288+
returned only once.
288289
"""
290+
fs = set(fs)
289291
with _AcquireFutures(fs):
290-
done = set(f for f in fs
291-
if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
292-
not_done = set(fs) - done
293-
292+
done = {f for f in fs
293+
if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]}
294+
not_done = fs - done
294295
if (return_when == FIRST_COMPLETED) and done:
295296
return DoneAndNotDoneFutures(done, not_done)
296297
elif (return_when == FIRST_EXCEPTION) and done:
@@ -309,7 +310,7 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
309310
f._waiters.remove(waiter)
310311

311312
done.update(waiter.finished_futures)
312-
return DoneAndNotDoneFutures(done, set(fs) - done)
313+
return DoneAndNotDoneFutures(done, fs - done)
313314

314315
class Future(object):
315316
"""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
@@ -564,6 +564,14 @@ def test_shutdown_no_wait(self):
564564

565565

566566
class WaitTests:
567+
def test_20369(self):
568+
# See https://bugs.python.org/issue20369
569+
future = self.executor.submit(time.sleep, 1.5)
570+
done, not_done = futures.wait([future, future],
571+
return_when=futures.ALL_COMPLETED)
572+
self.assertEqual({future}, done)
573+
self.assertEqual(set(), not_done)
574+
567575

568576
def test_first_completed(self):
569577
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