有没有办法检查pid是否对应于有效进程?我从其他来源获取pid os.getpid()
,我需要检查计算机上是否不存在具有该pid的进程。
我需要它在Unix和Windows中可用。我也在检查PID是否未使用。
有没有办法检查pid是否对应于有效进程?我从其他来源获取pid os.getpid()
,我需要检查计算机上是否不存在具有该pid的进程。
我需要它在Unix和Windows中可用。我也在检查PID是否未使用。
Answers:
如果pid没有运行,则向pid发送信号0将引发OSError异常,否则不执行任何操作。
import os
def check_pid(pid):
""" Check For the existence of a unix pid. """
try:
os.kill(pid, 0)
except OSError:
return False
else:
return True
os.kill(pid, 0)
与os.kill(pid, signal.CTRL_C_EVENT)
可能终止进程(或失败)的相同。当我在子流程上尝试时,我得到了一个OSError
位置errno==EINVAL
。
看一下psutil
模块:
psutil(Python系统和进程实用程序)是一个跨平台的库,用于检索有关Python中正在运行的进程和系统利用率(CPU,内存,磁盘,网络)的信息。[...]它目前支持32位和64位体系结构的Linux,Windows,OSX,FreeBSD和Sun Solaris,Python版本从2.6到3.4(Python 2.4和2.5的用户可以使用2.1.3版本) 。PyPy也可以工作。
它具有一个称为的函数pid_exists()
,可用于检查具有给定pid的进程是否存在。
这是一个例子:
import psutil
pid = 12345
if psutil.pid_exists(pid):
print("a process with pid %d exists" % pid)
else:
print("a process with pid %d does not exist" % pid)
以供参考:
mluebke代码不是100%正确;kill()还会引发EPERM(访问被拒绝),在这种情况下,这显然意味着存在进程。这应该工作:
(根据Jason R. Coombs评论编辑)
import errno
import os
def pid_exists(pid):
"""Check whether pid exists in the current process table.
UNIX only.
"""
if pid < 0:
return False
if pid == 0:
# According to "man 2 kill" PID 0 refers to every process
# in the process group of the calling process.
# On certain systems 0 is a valid PID but we have no way
# to know that in a portable fashion.
raise ValueError('invalid PID 0')
try:
os.kill(pid, 0)
except OSError as err:
if err.errno == errno.ESRCH:
# ESRCH == No such process
return False
elif err.errno == errno.EPERM:
# EPERM clearly means there's a process to deny access to
return True
else:
# According to "man 2 kill" possible error values are
# (EINVAL, EPERM, ESRCH)
raise
else:
return True
除非您使用pywin32,ctypes或C扩展模块,否则无法在Windows上执行此操作。如果可以从外部库中获取依赖,则可以使用psutil:
>>> import psutil
>>> psutil.pid_exists(2353)
True
仅当所讨论的进程归运行测试的用户所有时,涉及向进程发送“信号0”的答案才有效。否则,即使pid存在于系统中,您也将OSError
由于权限而获得权限。
为了绕过此限制,您可以检查是否/proc/<pid>
存在:
import os
def is_running(pid):
if os.path.isdir('/proc/{}'.format(pid)):
return True
return False
显然,这仅适用于基于Linux的系统。
OSError
由于拒绝许可而导致的许可可以与其他许可区别开来-通过查看errno或捕获来自的更专业的PermissionError
/ ProcessLookupError
例外OSError
。此外,仅当该进程存在时,您才会获得权限错误。因此,您的示例只是在Linux和其他Unices上运行的另一种方法,但是比正确调用并不完整os.kill(pid, 0)
。
/proc
procfs仅在Linux上退出,甚至在BSD或OSX上都不退出。
在Python 3.3+中,可以使用异常名称代替errno常量。Posix版本:
import os
def pid_exists(pid):
if pid < 0: return False #NOTE: pid == 0 returns True
try:
os.kill(pid, 0)
except ProcessLookupError: # errno.ESRCH
return False # No such process
except PermissionError: # errno.EPERM
return True # Operation not permitted (i.e., process exists)
else:
return True # no error, we can send a signal to the process
在此处查找特定于Windows的方法,以获取运行进程及其ID的完整列表。就像
from win32com.client import GetObject
def get_proclist():
WMI = GetObject('winmgmts:')
processes = WMI.InstancesOf('Win32_Process')
return [process.Properties_('ProcessID').Value for process in processes]
然后,您可以根据此列表验证pid。我对性能成本一无所知,因此,如果您要经常进行pid验证,则最好检查一下。
对于* NIx,只需使用mluebke的溶液即可。
在ntrrgc的基础上,我增强了Windows版本,因此它检查进程退出代码并检查权限:
def pid_exists(pid):
"""Check whether pid exists in the current process table."""
if os.name == 'posix':
import errno
if pid < 0:
return False
try:
os.kill(pid, 0)
except OSError as e:
return e.errno == errno.EPERM
else:
return True
else:
import ctypes
kernel32 = ctypes.windll.kernel32
HANDLE = ctypes.c_void_p
DWORD = ctypes.c_ulong
LPDWORD = ctypes.POINTER(DWORD)
class ExitCodeProcess(ctypes.Structure):
_fields_ = [ ('hProcess', HANDLE),
('lpExitCode', LPDWORD)]
SYNCHRONIZE = 0x100000
process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
if not process:
return False
ec = ExitCodeProcess()
out = kernel32.GetExitCodeProcess(process, ctypes.byref(ec))
if not out:
err = kernel32.GetLastError()
if kernel32.GetLastError() == 5:
# Access is denied.
logging.warning("Access is denied to get pid info.")
kernel32.CloseHandle(process)
return False
elif bool(ec.lpExitCode):
# print ec.lpExitCode.contents
# There is an exist code, it quit
kernel32.CloseHandle(process)
return False
# No exit code, it's running.
kernel32.CloseHandle(process)
return True
GetExistCodeProcess
要求,需要PROCESS_QUERY_INFORMATION
和PROCESS_QUERY_LIMITED_INFORMATION
访问权限。
GetExitCodeProcess
接收一个句柄和一个指针,并且在此示例中,ExitCodeProcess
当它仅是一个指针时,它将接收一个结构作为第二个参数。
结合GiampaoloRodolà对POSIX的回答和我对Windows 的回答,我得到了:
import os
if os.name == 'posix':
def pid_exists(pid):
"""Check whether pid exists in the current process table."""
import errno
if pid < 0:
return False
try:
os.kill(pid, 0)
except OSError as e:
return e.errno == errno.EPERM
else:
return True
else:
def pid_exists(pid):
import ctypes
kernel32 = ctypes.windll.kernel32
SYNCHRONIZE = 0x100000
process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
if process != 0:
kernel32.CloseHandle(process)
return True
else:
return False
GetExitCodeProcess
并确保您甚至具有访问权限。
在Windows中,您可以通过以下方式进行操作:
import ctypes
PROCESS_QUERY_INFROMATION = 0x1000
def checkPid(pid):
processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0,pid)
if processHandle == 0:
return False
else:
ctypes.windll.kernel32.CloseHandle(processHandle)
return True
首先,在此代码中,您尝试获取给定pid的进程的句柄。如果句柄有效,则关闭该句柄进行处理并返回True;否则,返回true。否则,您返回False。OpenProcess文档:https : //msdn.microsoft.com/zh-cn/library/windows/desktop/ms684320%28v=vs.85%29.aspx
例如,如果您要检查banshee是否正在运行,该功能将在Linux上运行...(banshee是音乐播放器)
import subprocess
def running_process(process):
"check if process is running. < process > is the name of the process."
proc = subprocess.Popen(["if pgrep " + process + " >/dev/null 2>&1; then echo 'True'; else echo 'False'; fi"], stdout=subprocess.PIPE, shell=True)
(Process_Existance, err) = proc.communicate()
return Process_Existance
# use the function
print running_process("banshee")
os.kill(pid, 0)
或查看相比,此方法显然逊色/proc/{pid}
。无需执行一个系统调用,您的代码不会派生一个孩子,而是在那个孩子中执行一个shell,该shell会解释您多余的迷你shell脚本,shell会派生另一个执行pgrep的孩子,最后pgrep进行迭代/proc
。您的答案没有回答发布的问题。OP要求提供给定PID的方法。您的方法需要一个进程名称。
我想将PID用于获得它的任何目的并优雅地处理错误。否则,这将是经典竞赛(当您检查PID有效时,PID可能有效,但稍后消失)