commit:     a4753096db30b4ec9c3953c54f906d3b48d2b679
Author:     Florian Schmaus <flow <AT> gentoo <DOT> org>
AuthorDate: Sat Sep 13 13:32:45 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Sep 14 03:14:10 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=a4753096

process: use an increasing poll-join delay

Do not use a fixed delay of 100ms in cases where we have to poll
join() (e.g., Python < 3.14). Instead start with a small delay of 2ms
and increase this delay by a factor until we reach 100ms. This helps
to quickly join short lived processes.

Before this change:

( cd lib; python3.13 -m timeit -n 10 'import portage.process; 
portage.process.spawn("true")' )
10 loops, best of 5: 106 msec per loop

After this change:

( cd lib; python3.13 -m timeit -n 10 'import portage.process; 
portage.process.spawn("true")' )
10 loops, best of 5: 8.9 msec per loop

Bug: https://bugs.gentoo.org/962721
Bug: https://bugs.gentoo.org/958635
Signed-off-by: Florian Schmaus <flow <AT> gentoo.org>
Part-of: https://github.com/gentoo/portage/pull/1463
Closes: https://github.com/gentoo/portage/pull/1463
Signed-off-by: Sam James <sam <AT> gentoo.org>

 lib/portage/process.py | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/lib/portage/process.py b/lib/portage/process.py
index e17eaf3c33..ee1d584364 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -428,10 +428,6 @@ class MultiprocessingProcess(AbstractProcess):
     An object that wraps OS processes created by multiprocessing.Process.
     """
 
-    # Number of seconds between poll attempts for process exit status
-    # (after the sentinel has become ready).
-    _proc_join_interval = 0.1
-
     def __init__(self, proc: multiprocessing.Process):
         self._proc = proc
         self.pid = proc.pid
@@ -485,11 +481,23 @@ class MultiprocessingProcess(AbstractProcess):
         # Now that proc.sentinel is ready, join on proc.
 
         async def join_via_polling(proc):
+            # Initial number of seconds between poll attempts for
+            # process exit status.
+            proc_join_interval_initial = 0.002
+            # Maximum number of seconds between poll attempts.
+            proc_join_interval_max = 0.1
+            # Factory by which the poll interval increases.
+            proc_join_interval_factor = 1.3
+
+            delay = proc_join_interval_initial
             while True:
                 proc.join(0)
                 if proc.exitcode is not None:
                     break
-                await asyncio.sleep(self._proc_join_interval, loop=loop)
+                delay *= proc_join_interval_factor
+                if delay > proc_join_interval_max:
+                    delay = proc_join_interval_max
+                await asyncio.sleep(delay, loop=loop)
 
         # We can only safely create a new thread to await the join if
         # we use 'forkserver' or 'spawn'.

Reply via email to