如何在 Python 中检查是否存在具有给定 pid 的进程?

是否有检查 pid 是否对应于有效进程的方法?我从 os.getpid()以外的其他来源获得一个 pid,我需要检查机器上是否存在具有该 pid 的进程。

我需要它在 Unix 和 Windows 中可用。我也检查,看看是否 PID 不在使用。

144880 次浏览

如果 pid 没有运行,将信号0发送到 pid 将引发 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

查看 给你中特定于窗口的获取带有 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 的解决方案。

我会说,无论您为什么目的获取 PID,都要使用它,并优雅地处理错误。否则,这就是一场经典的比赛(当您检查 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、 ctype 或 C 扩展模块,否则不能在 Windows 上这样做。 如果你可以依赖外部库,你可以使用 Psutil:

>>> import psutil
>>> psutil.pid_exists(2353)
True

看看 psutil模块:

Psutil (Python 系统和进程实用程序)是一个跨平台库,用于在 Python 中检索关于 正在运行的进程系统利用率(CPU、内存、磁盘、网络)的信息。[ ... ]它目前支持 Linux窗户OSXFreeBSD太阳索拉里斯,两者都是 32位64位架构,使用来自 2.6至3.4的 Python 版本(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)

参考资料:

结合 Giampaolo Rodolà 对 POSIX 的回答我的窗户我得到了这个:

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

在 Python 3.3 + 中,可以使用异常名称而不是 errno 常量:

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

在 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

这将工作于 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")

在 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; 否则返回 False。OpenProcess 文档: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx

答案涉及发送’信号0’的进程将工作 只有当所涉及的进程为运行测试的用户所有时,才能使用。否则,即使系统中存在 pid,也会由于 权限而得到 OSError

为了绕过这个限制,你可以检查 /proc/<pid>是否存在:

import os


def is_running(pid):
if os.path.isdir('/proc/{}'.format(pid)):
return True
return False

显然,这只适用于基于 Linux 的系统。

下面的代码同时适用于 Linux 和 Windows,并且不依赖于外部模块

import os
import subprocess
import platform
import re


def pid_alive(pid:int):
""" Check For whether a pid is alive """




system = platform.uname().system
if re.search('Linux', system, re.IGNORECASE):
try:
os.kill(pid, 0)
except OSError:
return False
else:
return True
elif re.search('Windows', system, re.IGNORECASE):
out = subprocess.check_output(["tasklist","/fi",f"PID eq {pid}"]).strip()
# b'INFO: No tasks are running which match the specified criteria.'


if re.search(b'No tasks', out, re.IGNORECASE):
return False
else:
return True
else:
raise RuntimeError(f"unsupported system={system}")

如果您需要,它可以很容易地增强

  1. 其他平台
  2. 其他语言

我发现这个解决方案似乎在 windows 和 linux 中都能很好地工作。

import psutil
import subprocess
import os
p = subprocess.Popen(['python', self.evaluation_script],stdout=subprocess.PIPE, stderr=subprocess.STDOUT)


pid = p.pid


def __check_process_running__(self,p):
if p is not None:
poll = p.poll()
if poll == None:
return True
return False
    

def __check_PID_running__(self,pid):
"""
Checks if a pid is still running (UNIX works, windows we'll see)
Inputs:
pid - process id
returns:
True if running, False if not
"""
if (platform.system() == 'Linux'):
try:
os.kill(pid, 0)
if pid<0:               # In case code terminates
return False
except OSError:
return False
else:
return True
elif (platform.system() == 'Windows'):
return pid in (p.pid for p in psutil.process_iter())

Windows 的另一个选择是通过 pywin32包:

pid in win32process.EnumProcesses()

Win32process.EnumProcessions ()返回当前正在运行的进程的 PID。

在尝试了不同的解决方案之后,依靠 Psutil是准确判断 PID 是否存在的最佳操作系统不可知方法。如上所述,psutil.pid_exists(pid)按预期工作,但缺点是,它包括过时的进程 ID 和最近终止的进程。

解决方案: 检查进程 ID 是否存在以及它是否正在积极运行。

import psutil


def process_active(pid: int or str) -> bool:
try:
process = psutil.Process(pid)
except psutil.Error as error:  # includes NoSuchProcess error
return False
if psutil.pid_exists(pid) and process.status() == psutil.STATUS_RUNNING:
return True