-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Eliminate busy-loop in psutil.wait_procs() #2712
Description
In #2706 we eliminated the busy loop from Process.wait() by adopting an event-driven approach. psutil.wait_procs() (which waits for multiple PIDs, see doc) could benefit from a similar improvement.
Linux
select.poll() can efficiently wait for multiple PIDs at once. However, the downside is that each call to os.pidfd_open() consumes one file descriptor per monitored PID. If the number of PIDs is large, the process can hit the per-process FD limit (typically 1024) and fail with EMFILE. This limit can be increased (assuming the hard limit allows it) with:
import resource
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
new_soft = min(soft * 4, hard)
if new_soft > soft:
resource.setrlimit(resource.RLIMIT_NOFILE, (new_soft, hard))...still, it's not something we can rely on. Possible solutions:
- use a fallback mechanism (use
pidfd_open()first, else fallback to the busy loop approach) - like above (use a fallback) and, in addition, determine the file descriptor limit first (e.g. 1024) and only use the fast path if the number of PIDs is less than half that limit (512); otherwise fall back, to avoid exhausting the process’s file descriptors.
- use
AF_LINK+PROC_EVENT_EXITto monitor gone PIDs, see partial idea in An API for monitoring new PIDs / processes #2348. Drawback: it could actually be worse in case many PIDs are created while waiting.
BSD / macOS
The easy one. We can simply use kqueue() + KQ_FILTER_PROC + KQ_NOTE_EXIT as we're doing right now, we'll just pass multiple PIDs instead of 1.
Windows
We can use WaitForMultipleObjects().