有没有一种方法可以检查pid是否对应于有效的进程? 我从不同于os.getpid()
的来源获取pid,并且需要检查该pid所对应的进程不存在于机器上。
我需要在Unix和Windows系统中使用。我还要检查PID是否未被使用。
向进程ID发送信号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
在Windows上被支持,但是os.kill(pid, 0)
和os.kill(pid, signal.CTRL_C_EVENT)
是相同的,这可能会终止进程(或失败)。当尝试对子进程执行此操作时,会出现OSError
,其中errno==EINVAL
。 - Jason R. Coombs请看psutil
模块:
psutil(python系统和进程工具)是一个跨平台的库,可以在Python中检索有关运行进程和系统利用率(CPU、内存、磁盘、网络)的信息[...]。它目前支持Linux、Windows、OSX、FreeBSD和Sun Solaris,包括32位和64位架构,使用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)
参考资料:
psutil
在POSIX系统中实现pid_exists()
的方式。请看这个链接:https://github.com/giampaolo/psutil/blob/5ba055a8e514698058589d3b615d408767a6e330/psutil/_psposix.py#L28-L53。与`psutil`作者Giampaolo Rodolà在StackOverflow上的回答(https://dev59.com/enRB5IYBdhLWcg3wn4fb#6940314)进行比较。 - jfsmluebke的代码并非完全正确;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
如果你使用的是 Windows 操作系统,则无法直接实现此功能,除非你使用 pywin32、ctypes 或者 C 扩展模块。如果可以接受依赖于外部库,则可以使用 psutil:
>>> import psutil
>>> psutil.pid_exists(2353)
True
ProcessLookupError
继承自OSError
。 - maxschlepzig如果涉及向进程发送“信号0”的答案仅在该进程归属于运行测试的用户时才有效。否则,即使pid存在于系统中,由于权限问题,您也将收到一个OSError。
为了绕过这个限制,您可以检查/proc/是否存在:
import os
def is_running(pid):
if os.path.isdir('/proc/{}'.format(pid)):
return True
return False
这仅适用于基于Linux的系统,显然。
OSError
由于权限被拒绝可以通过查看errno或捕获更专业的PermissionError
/ProcessLookupError
异常来区分其他错误。此外,仅当进程存在时才会收到权限错误。因此,您的示例只是在Linux和其他一些Unix上运行的替代方法,但它并不比正确调用os.kill(pid, 0)
更完整。 - maxschlepzig/proc
procfs仅存在于Linux上,甚至在BSD或OSX上也不存在。 - C.W.在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
查看这里,以获取获取运行进程及其ID的Windows特定方式。大致如下:
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]
在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
GetExitCodeProcess
接收一个句柄和一个指针,但在此示例中,它将 ExitCodeProcess
结构作为第二个参数接收,而应该只是一个指针。 - Fabio Zadrozny结合Giampaolo Rodolà关于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
并确保您有访问权限。 - speedplanekernel32.OpenProcess
是不够的。正如这里所指出的那样,"如果进程最近退出,则 pid 可能仍然存在于句柄中。" 如果 kernel32.OpenProcess
返回非零值,我们仍然需要进一步使用 kernel32.GetExitCodeProcess
来检查退出代码。 - Meowimport 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;否则返回False。OpenProcess文档:https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx
例如,如果您想检查banshee音乐播放器是否正在运行,这将适用于Linux……
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}
相比明显劣质。你的代码不是执行一个系统调用,而是fork一个子进程,在该子进程中执行shell,shell解释你多余的小型shell脚本,shell再fork另一个子进程来执行pgrep,最后pgrep迭代 /proc
。你的回答并没有回答提问者的问题。OP要求给定PID的方法,而你的方法需要进程名称。 - maxschlepzig
import subprocess; subprocess.check_call('ps -p 12345', shell=True);
,而跨平台使用则需要psutil
。 - Trevor Boyd Smith