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

问题描述 投票:0回答:15

有没有办法检查pid是否对应于有效的进程?我从

os.getpid()
以外的其他来源获取 pid,并且我需要检查机器上是否不存在具有该 pid 的进程。

我需要它在 Unix 和 Windows 中可用。我也在检查 PID 是否未被使用。

python process pid
15个回答
191
投票

如果 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

109
投票

看看

psutil
模块:

psutil(Python 系统和进程实用程序)是一个跨平台库,用于在 Python 中检索有关 正在运行的进程系统利用率(CPU、内存、磁盘、网络)的信息。 [...] 目前支持 LinuxWindowsOSXFreeBSDSun Solaris32 位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)

供参考:


70
投票

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

24
投票

涉及向进程发送“信号 0”的答案才有效仅当相关进程由运行测试的用户拥有时。否则,即使 pid 存在于系统中,您也会因

permissions
而得到 OSError

为了绕过此限制,您可以检查

/proc/<pid>
是否存在:

import os

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

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


11
投票

在 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

9
投票

查看此处,了解 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的解决方案即可。


7
投票

在 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

4
投票

结合 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

2
投票

在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 的进程的句柄。如果句柄有效,则关闭process的句柄并返回True;否则,您将返回 False。 OpenProcess 文档:https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx


2
投票

这适用于 Linux,例如,如果您想检查 banshee 是否正在运行...(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")

1
投票

尝试不同的解决方案后,依靠 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
    return False

0
投票

以下代码适用于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. 其他语言

0
投票

我发现这个解决方案似乎在 Windows 和 Linux 上都运行良好。我用 psutil 来检查。

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())

0
投票

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

pid in win32process.EnumProcesses()

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


-2
投票

我想说,无论您获取 PID 的目的是什么,都可以使用它并妥善处理错误。否则,这就是一场经典的比赛(当你检查它是否有效时,PID可能是有效的,但稍后就会消失)

© www.soinside.com 2019 - 2024. All rights reserved.