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

131 人关注

有什么方法可以检查一个pid是否对应于一个有效的进程?我从一个不同的来源得到一个pid,而不是从 os.getpid() 得到的,我需要检查这个pid的进程是否在机器上不存在。

我需要它在Unix和Windows中可用。我还在检查该PID是否正在使用。

5 个评论
Windows是一个非标准的操作系统。 这类东西是不可移植的。 知道你不能同时拥有这两样东西,你的优先事项是什么? 选择一个作为优先事项,然后编辑这个问题。
@S.Lott Windows是一个非标准的操作系统 这是我见过的最愚蠢的言论之一...。
@Piotr Dobrogost:你能提供处理POSIX标准unix和非POSIX标准Windows的代码吗?如果可以,请提供一个答案,(a)解决这个问题,(b)明确Windows以某种方式符合POSIX标准。
@PiotrDobrogost 我认为S.Lott的言论更多的是关于实施细节和API支持,而不是市场份额。
Windows与其他流行的操作系统的共同点肯定比其他操作系统的共同点少。(任何做网络开发的人都可能把它比作类似于微软的臭名昭著的产品)。但是在回答@S.Lott的问题时:我很少为Windows写Python代码,因为它不应该在Linux、OSX、BSD等系统上工作,所以我真的不认为 "优先选择 "是有用的建议,尤其是Python尽可能地抽象了平台差异。
python
process
pid
Evan Fosmark
Evan Fosmark
发布于 2009-02-20
14 个回答
mluebke
mluebke
发布于 2009-02-20
已采纳
0 人赞同

向一个pid发送信号0,如果这个pid没有运行,将引发一个OSError异常,否则不做任何处理。

import os
def check_pid(pid):        
    """ Check For the existence of a unix pid. """
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True
    
在linux和OSX中肯定是有效的,我不能说Windows。它并不像你问的那样杀死进程,它发送信号0,基本上是 "你在运行吗?"。
这在Windows上肯定是不行的,因为没有类似UNIX的信号这回事。
为了完整起见,你还应该检查错误号,确保它是3(捕获异常并检查第一个参数)。如果目标进程存在,但你没有发送信号的权限(无论什么原因),这就很重要了。
os.kill在Windows上被支持,但 os.kill(pid, 0) os.kill(pid, signal.CTRL_C_EVENT) 相同,可能会终止进程(或失败)。当我在一个子进程上尝试这样做时,我得到了一个 OSError ,其中 errno==EINVAL
moooeeeep
moooeeeep
发布于 2009-02-20
0 人赞同

请看一下 psutil module:

psutil (Python system和process utilities)是一个跨平台的库,用于检索有关 running processes 系统利用 (CPU, memory, disks, network) in Python. [...] It currently supports Linux , Windows , OSX , FreeBSD Sun Solaris , both 32-bit 64-bit 架构,其Python版本从 2.6 to 3.4 (users of Python 2.4和2.5 may use 2.1.3 version). PyPy is also known to work.

它有一个叫做 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)

For reference:

  • https://pypi.python.org/pypi/psutil
  • https://github.com/giampaolo/psutil
  • http://pythonhosted.org/psutil/#psutil.pid_exists
  • 我有一个实例,pid_exists在Windows上不再可靠。 它错误地报告死掉的pid正在被使用。 这提醒我们要不时地更新你的psutil模块--特别是在进行操作系统升级时。
    Giampaolo Rodolà
    Giampaolo Rodolà
    发布于 2009-02-20
    0 人赞同

    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')
            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)
        
    haridsv建议测试应该是e.errno != 3;也许是e.errno != errno.ESRCH
    为什么?ESRCH意味着 "没有这样的过程"。
    对。因为ESRCH意味着 "没有这样的进程",errno != ESRCH意味着 "不是没有这样的进程 "或 "进程存在",这与函数的名称非常相似。你特别提到了EPERM,但其他可能的错误代码意味着什么?单独挑出一个与检查意图松散相关的错误代码似乎不正确,而ESRCH似乎密切相关。
    你是对的。我编辑了代码,现在反映了你的建议。
    in python3 os.kill() throws ProcessLookupError
    Omer Dagan
    Omer Dagan
    发布于 2009-02-20
    0 人赞同

    涉及到向进程发送 "信号0 "的答案将起作用 only if the process in question is owned by the user running the test .否则你会得到一个 OSError ,由于 permissions , even if the pid exists in the system.

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

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

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

    jfs
    wrong. 替换代码0】表示PID存在 , you get ProcessLookupError if pid doesn't exist.
    由于被拒绝的权限导致的 OSError 可以和其他的区分开来--通过查看errno或者通过捕捉更专业的 PermissionError / ProcessLookupError 异常,这些异常来自于 OSError 。此外,只有当进程存在时,你才会得到权限错误。因此,你的例子只是一种替代方法,在Linux和其他一些Unices上可以使用,但它并不比正确调用 os.kill(pid, 0) 更完整。
    C.W.
    这个解决方案不是corss平台的。OP希望它能在Unix和Windows上使用。 /proc procfs只在Linux上退出,甚至在BSD或OSX上也没有。
    如果/proc被挂载hidepid=2,这个方法就会失败,如果进程被其他用户拥有,就不会显示在列表中。
    jfs
    jfs
    发布于 2009-02-20
    0 人赞同

    在 Python 3.3+ 中,你可以用异常名称代替 errno 常量。 Posix version :

    import os
    def pid_exists(pid): 
        if pid < 0: return False #NOTE: pid == 0 returns True
            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
        
    Alexander Lebedev
    Alexander Lebedev
    发布于 2009-02-20
    0 人赞同

    Look here 为获得运行中的进程及其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]
    

    然后你可以根据这个列表来验证你得到的pid。 我对性能成本没有概念,所以如果你要经常做pid验证的话,你最好检查一下这个。

    For *NIx, just use mluebke's solution.

    这对我来说很有效。我想检查进程名称,所以把 "ProcessID "换成了 "Name",并把它转换为列表中的检查,返回True或False。
    speedplane
    speedplane
    发布于 2009-02-20
    0 人赞同

    在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
                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
        
    augustomen
    实际上,根据 msdn.microsoft.com/en-us/library/windows/desktop/... , GetExistCodeProcess requires the PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION access rights.
    请注意,这段代码是错误的。 GetExitCodeProcess 接收一个句柄和一个指针,在这个例子中,它接收了一个 ExitCodeProcess 结构作为第二个参数,而它应该只是一个指针。
    在OpenProcess之后,检查GetLastError是一个好主意。那里的ERROR_ACCESS_DENIED意味着该进程存在!这里有一个完整的例子,使用这个。 gist.github.com/ociule/8a48d2a6b15f49258a87b5f55be29250
    Alicia
    Alicia
    发布于 2009-02-20
    0 人赞同

    Combining Giampaolo Rodolà 对 POSIX 的回答 mine for Windows I got this:

    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
                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
        
    在windows 8.1上,windows版本对我不起作用。你必须检查 GetExitCodeProcess ,并确保你甚至有权限。
    Meow
    仅仅使用 kernel32.OpenProcess 是不够的。由于 here pointed out "如果该进程最近退出了,则该句柄的pid可能仍然存在。" 如果 kernel32.OpenProcess 返回非零值,我们仍然需要 kernel32.GetExitCodeProcess 来进一步检查退出代码。
    Andrei
    Andrei
    发布于 2009-02-20
    0 人赞同

    在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

    BARSPIN
    BARSPIN
    发布于 2009-02-20
    0 人赞同

    这将适用于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")
        
    与使用 os.kill(pid, 0) 或查看 /proc/{pid} 相比,这种方法显然是低劣的。你的代码不是执行一个系统调用,而是分叉一个子程序,在这个子程序中执行一个shell,这个shell解释你多余的小型shell脚本,这个shell分叉另一个子程序,执行pgrep,最后pgrep迭代 /proc 。你的答案并没有回答发布的问题。OP问的是一个给定PID的方法。你的方法需要一个进程名称。
    oldpride
    oldpride
    发布于 2009-02-20
    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):
                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}")
    

    在你需要的情况下,它可以很容易地增强

  • other platforms
  • other language
  • Pat
    Pat
    发布于 2009-02-20
    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'):
                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())
        
    ROJI
    ROJI
    发布于 2009-02-20
    0 人赞同

    Windows的另一个选择是通过pywin32软件包。