]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-20369: concurrent.futures.wait() now deduplicates futures given a… (GH-30168)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 4 Jan 2022 14:27:26 +0000 (06:27 -0800)
committerGitHub <noreply@github.com>
Tue, 4 Jan 2022 14:27:26 +0000 (06:27 -0800)
* 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 7d7817cf0f826e566d8370a0e974bbfed6611d91)

Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Doc/library/concurrent.futures.rst
Lib/concurrent/futures/_base.py
Lib/test/test_concurrent_futures.py
Misc/NEWS.d/next/Library/2021-12-17-12-06-40.bpo-20369.zzLuBz.rst [new file with mode: 0644]

index 897efc2f544426d450b9defd1bd735c7a0836260..f62b5e35463046d721f6a4667acc0dfd96955ca8 100644 (file)
@@ -435,7 +435,8 @@ Module Functions
 .. function:: wait(fs, timeout=None, return_when=ALL_COMPLETED)
 
    Wait for the :class:`Future` instances (possibly created by different
-   :class:`Executor` instances) given by *fs* to complete.  Returns a named
+   :class:`Executor` instances) given by *fs* to complete. Duplicate futures
+   given to *fs* are removed and will be returned only once. Returns a named
    2-tuple of sets.  The first set, named ``done``, contains the futures that
    completed (finished or cancelled futures) before the wait completed.  The
    second set, named ``not_done``, contains the futures that did not complete
index 6095026cb278b9f3158505886416f094041c258d..5c00f2edbe5482092656422a01ea87ccc635eb35 100644 (file)
@@ -284,13 +284,14 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
         A named 2-tuple of sets. The first set, named 'done', contains the
         futures that completed (is finished or cancelled) before the wait
         completed. The second set, named 'not_done', contains uncompleted
-        futures.
+        futures. Duplicate futures given to *fs* are removed and will be 
+        returned only once.
     """
+    fs = set(fs)
     with _AcquireFutures(fs):
-        done = set(f for f in fs
-                   if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
-        not_done = set(fs) - done
-
+        done = {f for f in fs
+                   if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]}
+        not_done = fs - done
         if (return_when == FIRST_COMPLETED) and done:
             return DoneAndNotDoneFutures(done, not_done)
         elif (return_when == FIRST_EXCEPTION) and done:
@@ -309,7 +310,7 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
             f._waiters.remove(waiter)
 
     done.update(waiter.finished_futures)
-    return DoneAndNotDoneFutures(done, set(fs) - done)
+    return DoneAndNotDoneFutures(done, fs - done)
 
 class Future(object):
     """Represents the result of an asynchronous computation."""
index 48d56d9fdcb1eb6a8c6bc806a5f220f0de84ddfd..d693fb4ee199bb5042688a6f6d004e8d9ffd191d 100644 (file)
@@ -564,6 +564,14 @@ create_executor_tests(ProcessPoolShutdownTest,
 
 
 class WaitTests:
+    def test_20369(self):
+        # See https://bugs.python.org/issue20369
+        future = self.executor.submit(time.sleep, 1.5)
+        done, not_done = futures.wait([future, future],
+                            return_when=futures.ALL_COMPLETED)
+        self.assertEqual({future}, done)
+        self.assertEqual(set(), not_done)
+
 
     def test_first_completed(self):
         future1 = self.executor.submit(mul, 21, 2)
diff --git a/Misc/NEWS.d/next/Library/2021-12-17-12-06-40.bpo-20369.zzLuBz.rst b/Misc/NEWS.d/next/Library/2021-12-17-12-06-40.bpo-20369.zzLuBz.rst
new file mode 100644 (file)
index 0000000..cc5cd00
--- /dev/null
@@ -0,0 +1 @@
+:func:`concurrent.futures.wait` no longer blocks forever when given duplicate Futures. Patch by Kumar Aditya.