我意识到“快”有点主观所以我会用一些背景来解释。我正在研究一个名为psutil的Python模块,用于以跨平台的方式读取流程信息。其中一个函数是pid_exists(pid)
函数,用于确定PID是否在当前进程列表中。
现在我以明显的方式这样做,使用EnumProcesses()来拉取进程列表,然后通过列表进行交互并查找PID。但是,一些简单的基准测试表明,这比基于UNIX的平台(Linux,OS X,FreeBSD)上的pid_exists函数要慢得多,我们在kill(pid, 0)
上使用0信号来确定PID是否存在。额外的测试表明它的EnumProcesses几乎一直在占用。
任何人都知道比使用EnumProcesses更快的方法来确定PID是否存在?我尝试OpenProcess()并检查错误打开不存在的进程,但结果比迭代通过EnumProcesses列表慢4倍,因此也是如此。还有其他(更好的)建议吗?
注意:这是一个Python库,旨在避免第三方lib依赖项,如pywin32扩展。我需要一个比当前代码更快的解决方案,它不依赖于pywin32或标准Python发行版中没有的其他模块。
编辑:澄清一下 - 我们非常清楚阅读过程中存在固有的竞争条件。如果在数据收集过程中进程消失或者遇到其他问题,我们会引发异常。 pid_exists()函数无意替换正确的错误处理。
更新:显然我早期的基准测试存在缺陷 - 我在C中编写了一些简单的测试应用程序,EnumProcesses一直出现速度较慢而OpenProcess(如果PID有效,则与GetProcessExitCode结合使用但是过程有实际上更快并不慢。
答案 0 :(得分:8)
OpenProcess可以告诉你没有列举所有内容。我不知道有多快。
编辑:请注意,即使您从GetExitCodeProcess
获得句柄,也需要OpenProcess
来验证流程的状态。
答案 1 :(得分:4)
使用pid_exists函数时存在固有的竞争条件:当调用程序使用答案时,该进程可能已经消失,或者可能已创建具有查询ID的新进程。我敢说任何使用此功能的应用程序都存在设计缺陷,因此优化此功能是不值得的。
答案 2 :(得分:3)
事实证明我的基准测试显然存在缺陷,因为后来的测试显示OpenProcess和GetExitCodeProcess比使用EnumProcesses要快得多。我不确定发生了什么,但我做了一些新的测试并验证了这是更快的解决方案:
int pid_is_running(DWORD pid)
{
HANDLE hProcess;
DWORD exitCode;
//Special case for PID 0 System Idle Process
if (pid == 0) {
return 1;
}
//skip testing bogus PIDs
if (pid < 0) {
return 0;
}
hProcess = handle_from_pid(pid);
if (NULL == hProcess) {
//invalid parameter means PID isn't in the system
if (GetLastError() == ERROR_INVALID_PARAMETER) {
return 0;
}
//some other error with OpenProcess
return -1;
}
if (GetExitCodeProcess(hProcess, &exitCode)) {
CloseHandle(hProcess);
return (exitCode == STILL_ACTIVE);
}
//error in GetExitCodeProcess()
CloseHandle(hProcess);
return -1;
}
请注意,您确实需要使用GetExitCodeProcess()
,因为OpenProcess()
将在最近死亡的进程上成功,因此您无法假设有效的进程句柄意味着进程正在运行。
另请注意,OpenProcess()
对于任何有效PID(参见Why does OpenProcess succeed even when I add three to the process ID?)<3之内的PID成功(参见{{3}})
答案 3 :(得分:3)
我用这种方式编码Jay的最后一个功能。
int pid_is_running(DWORD pid){
HANDLE hProcess;
DWORD exitCode;
//Special case for PID 0 System Idle Process
if (pid == 0) {
return 1;
}
//skip testing bogus PIDs
if (pid < 0) {
return 0;
}
hProcess = handle_from_pid(pid);
if (NULL == hProcess) {
//invalid parameter means PID isn't in the system
if (GetLastError() == ERROR_INVALID_PARAMETER) {
return 0;
}
//some other error with OpenProcess
return -1;
}
DWORD dwRetval = WaitForSingleObject(hProcess, 0);
CloseHandle(hProcess); // otherwise you'll be losing handles
switch(dwRetval) {
case WAIT_OBJECT_0;
return 0;
case WAIT_TIMEOUT;
return 1;
default:
return -1;
}
}
主要区别在于关闭进程句柄(当此函数的客户端长时间运行时很重要)和进程终止检测策略。 WaitForSingleObject让您有机会等待一段时间(将0更改为函数参数值),直到进程结束。