From 4ff98344874d0db17930a025ce552ce01a89176c Mon Sep 17 00:00:00 2001 From: ShreyNaithani Date: Fri, 6 Mar 2026 20:47:41 +0500 Subject: [PATCH 1/9] gh-145587: fix busy loop in multiprocessing.connection.wait on Windows Ensure wait() blocks for the specified timeout when object_list is empty, preventing 100% CPU usage. This aligns the Windows behavior with the Unix implementation. --- Lib/multiprocessing/connection.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 41b36066c62fcb..e6aa2beac2092c 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -1085,6 +1085,14 @@ def wait(object_list, timeout=None): Returns list of those objects in object_list which are ready/readable. ''' + if not object_list: + if timeout is None: + while True: + time.sleep(1e6) + elif timeout > 0: + time.sleep(timeout) + return [] + if timeout is None: timeout = INFINITE elif timeout < 0: From 9be351a045afeafe4994a7a1bc8c48b13aea53bf Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 14:34:41 +0000 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst diff --git a/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst b/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst new file mode 100644 index 00000000000000..a58e6d8edaffb2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst @@ -0,0 +1 @@ +Resolved a performance regression in `multiprocessing.connection.wait` on Windows that caused infinite busy loops when called with no objects. The function now properly yields control to the OS to conserve CPU resources. From b5527c251f1dd0a514d3f07ba25343209792ca4c Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sat, 7 Mar 2026 19:37:28 +0500 Subject: [PATCH 3/9] Fix formatting in NEWS entry --- .../next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst b/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst index a58e6d8edaffb2..5f1254e6f89417 100644 --- a/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst +++ b/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst @@ -1 +1 @@ -Resolved a performance regression in `multiprocessing.connection.wait` on Windows that caused infinite busy loops when called with no objects. The function now properly yields control to the OS to conserve CPU resources. +Resolved a performance regression in ``multiprocessing.connection.wait`` on Windows that caused infinite busy loops when called with no objects. The function now properly yields control to the OS to conserve CPU resources. From b0676edc9efe1bf1488dd8bb41dd28f2f73757ba Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sun, 8 Mar 2026 11:59:56 +0500 Subject: [PATCH 4/9] Apply suggestion from @aisk Co-authored-by: AN Long --- Lib/multiprocessing/connection.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index e6aa2beac2092c..8fa40320419653 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -1085,6 +1085,8 @@ def wait(object_list, timeout=None): Returns list of those objects in object_list which are ready/readable. ''' + object_list = list(object_list) + if not object_list: if timeout is None: while True: From eeb8e6ae7108fde793fd70d5a78ccdb0cbbabfba Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sun, 8 Mar 2026 12:31:43 +0500 Subject: [PATCH 5/9] Update _test_multiprocessing.py --- Lib/test/_test_multiprocessing.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index cc07062eee6f98..0955b2dd8c5a34 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -3889,6 +3889,16 @@ def test_context(self): self.assertTrue(b.closed) self.assertRaises(OSError, a.recv) self.assertRaises(OSError, b.recv) + + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() + def test_wait_empty(self): + # gh-145587: wait() with empty list should respect timeout + timeout = 0.5 + start = time.monotonic() + res = self.connection.wait([], timeout=timeout) + duration = time.monotonic() - start + self.assertEqual(res, []) + self.assertGreaterEqual(duration, timeout - 0.1) class _TestListener(BaseTestCase): From 152c675d3379a6c4d7f4bf3a16d77c1d008aedcf Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sun, 8 Mar 2026 12:35:41 +0500 Subject: [PATCH 6/9] cleanup --- Lib/test/_test_multiprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 0955b2dd8c5a34..992a4f7c274fea 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -3889,7 +3889,7 @@ def test_context(self): self.assertTrue(b.closed) self.assertRaises(OSError, a.recv) self.assertRaises(OSError, b.recv) - + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() def test_wait_empty(self): # gh-145587: wait() with empty list should respect timeout From 360ef282a894151681042aa6687c1a8635d7a83a Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sun, 8 Mar 2026 12:51:36 +0500 Subject: [PATCH 7/9] Cleanup --- Lib/multiprocessing/connection.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 8fa40320419653..9ce996c9ccd211 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -1101,8 +1101,6 @@ def wait(object_list, timeout=None): timeout = 0 else: timeout = int(timeout * 1000 + 0.5) - - object_list = list(object_list) waithandle_to_obj = {} ov_list = [] ready_objects = set() From a931bdfc9985e5b4ce43f95d3f309c43995edc4a Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sun, 8 Mar 2026 13:16:53 +0500 Subject: [PATCH 8/9] Skip test_wait_empty for non process types --- Lib/test/_test_multiprocessing.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 992a4f7c274fea..d67fd13fa33bed 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -3892,11 +3892,14 @@ def test_context(self): @warnings_helper.ignore_fork_in_thread_deprecation_warnings() def test_wait_empty(self): + if self.TYPE != 'processes': + self.skipTest('test not appropriate for {}'.format(self.TYPE)) # gh-145587: wait() with empty list should respect timeout timeout = 0.5 start = time.monotonic() res = self.connection.wait([], timeout=timeout) duration = time.monotonic() - start + self.assertEqual(res, []) self.assertGreaterEqual(duration, timeout - 0.1) From f41bfb4a4231222c25cd24f6819a663ae44a018f Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Sun, 8 Mar 2026 18:48:23 +0500 Subject: [PATCH 9/9] Update 2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst --- .../next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst b/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst index 5f1254e6f89417..c17d01f36b8c64 100644 --- a/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst +++ b/Misc/NEWS.d/next/Library/2026-03-07-14-34-39.gh-issue-145587.flFQ5-.rst @@ -1 +1 @@ -Resolved a performance regression in ``multiprocessing.connection.wait`` on Windows that caused infinite busy loops when called with no objects. The function now properly yields control to the OS to conserve CPU resources. +Resolved a performance regression in ``multiprocessing.connection.wait`` on Windows that caused infinite busy loops when called with no objects. The function now properly yields control to the OS to conserve CPU resources. Patch By Shrey Naithani