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'.