简体   繁体   English

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

[英]How to check if there exists a process with a given pid in Python?

Is there a way to check to see if a pid corresponds to a valid process?有没有办法检查 pid 是否对应于有效进程? I'm getting a pid from a different source other than from os.getpid() and I need to check to see if a process with that pid doesn't exist on the machine.我从os.getpid()以外的其他来源获取 pid,我需要检查机器上是否不存在具有该 pid 的进程。

I need it to be available in Unix and Windows. I'm also checking to see if the PID is NOT in use.我需要它在 Unix 和 Windows 中可用。我也在检查 PID 是否未被使用。

Sending signal 0 to a pid will raise an OSError exception if the pid is not running, and do nothing otherwise.如果 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

Have a look at the psutil module:看看psutil模块:

psutil (python system and process utilities) is a cross-platform library for retrieving information on running processes and system utilization (CPU, memory, disks, network) in Python. psutil (python 系统和进程实用程序)是一个跨平台库,用于在 Python 中检索有关正在运行的进程系统利用率(CPU、内存、磁盘、网络)的信息。 [...] It currently supports Linux , Windows , OSX , FreeBSD and Sun Solaris , both 32-bit and 64-bit architectures, with Python versions from 2.6 to 3.4 (users of Python 2.4 and 2.5 may use 2.1.3 version). [...] 目前支持LinuxWindowsOSXFreeBSDSun Solaris32 位64 位架构,Python 版本从2.6 到 3.4 (Python 2.4 和 2.5 的用户可以使用 2.1.3 版本) . PyPy is also known to work. PyPy 也可以工作。

It has a function called pid_exists() that you can use to check whether a process with the given pid exists.它有一个名为pid_exists()的函数,您可以使用它来检查具有给定 pid 的进程是否存在。

Here's an example:下面是一个例子:

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)

For reference:以供参考:

mluebke code is not 100% correct; mluebke 代码不是 100% 正确; kill() can also raise EPERM (access denied) in which case that obviously means a process exists. kill() 还可以引发 EPERM(拒绝访问),在这种情况下,这显然意味着存在进程。 This is supposed to work:这应该有效:

(edited as per Jason R. Coombs comments) (根据 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

You can't do this on Windows unless you use pywin32, ctypes or a C extension module.除非您使用 pywin32、ctypes 或 C 扩展模块,否则您无法在 Windows 上执行此操作。 If you're OK with depending from an external lib you can use psutil :如果您可以依赖外部库,则可以使用psutil

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

The answers involving sending 'signal 0' to the process will work only if the process in question is owned by the user running the test .只有当有问题的进程由运行测试的用户拥有时,涉及向进程发送“信号 0”的答案才会起作用。 Otherwise you will get an OSError due to permissions , even if the pid exists in the system.否则,即使 pid 存在于系统中,您也会因权限而收到OSError

In order to bypass this limitation you can check if /proc/<pid> exists:为了绕过这个限制,你可以检查/proc/<pid>存在:

import os

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

This applies to linux based systems only, obviously.显然,这仅适用于基于 linux 的系统。

In Python 3.3+, you could use exception names instead of errno constants.在 Python 3.3+ 中,您可以使用异常名称而不是 errno 常量。 Posix version : 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

Look here for windows-specific way of getting full list of running processes with their IDs. 在此处查找特定于 Windows 的方法,以获取正在运行的进程及其 ID 的完整列表。 It would be something like它会是这样的

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]

You can then verify pid you get against this list.然后,您可以根据此列表验证获得的 pid。 I have no idea about performance cost, so you'd better check this if you're going to do pid verification often.我不知道性能成本,所以如果你要经常做 pid 验证,你最好检查一下。

For *NIx, just use mluebke's solution.对于*NIx,只需使用mluebke 的解决方案。

Building upon ntrrgc's I've beefed up the windows version so it checks the process exit code and checks for permissions:建立在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

Combining Giampaolo Rodolà's answer for POSIX and mine for Windows I got this:结合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

This will work for Linux, for example if you want to check if banshee is running... (banshee is a music player)这适用于 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")

In Windows, you can do it in this way:在 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

First of all, in this code you try to get a handle for process with pid given.首先,在这段代码中,您尝试使用给定的 pid 获取进程的句柄。 If the handle is valid, then close the handle for process and return True;如果句柄有效,则关闭进程句柄并返回True; otherwise, you return False.否则,您将返回 False。 Documentation for OpenProcess: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx OpenProcess 文档: https : //msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx

The following code works on both Linux and Windows, and not depending on external modules以下代码适用于 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}")

It can be easily enhanced in case you need如果您需要,它可以轻松增强

  1. other platforms其他平台
  2. other language其他语言

I found that this solution seems to work well in both windows and linux.我发现这个解决方案似乎在 windows 和 linux 中都运行良好。 I used psutil to check.我用 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())

Another option for Windows is through the pywin32 package: Windows 的另一个选择是通过 pywin32 包:

pid in win32process.EnumProcesses()

The win32process.EnumProcesses() returns PIDs for currently running processes. win32process.EnumProcesses() 返回当前正在运行的进程的 PID。

After trying different solutions, relying on psutil was the best OS agnostic way to accurately say if a PID exists.在尝试了不同的解决方案之后,依靠psutil是准确判断 PID 是否存在的最佳操作系统不可知论方法。 As suggested above, psutil.pid_exists(pid) works as intended but the downside is, it includes stale process IDs and processes that were terminated recently.如上所述, psutil.pid_exists(pid)按预期工作,但缺点是,它包含陈旧的进程 ID 和最近终止的进程。

Solution: Check if process ID exists and if it is actively running.解决方案:检查进程 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

I'd say use the PID for whatever purpose you're obtaining it and handle the errors gracefully.我会说无论出于何种目的使用 PID 并优雅地处理错误。 Otherwise, it's a classic race (the PID may be valid when you check it's valid, but go away an instant later)否则,这是一场经典比赛(当您检查它有效时,PID 可能有效,但稍后会消失)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM