Как проверить, существует ли процесс с данным pid в Python? - PullRequest
91 голосов
/ 20 февраля 2009

Есть ли способ проверить, соответствует ли pid действительному процессу? Я получаю pid из другого источника, кроме os.getpid(), и мне нужно проверить, не существует ли процесс с таким pid на машине.

Мне нужно, чтобы он был доступен в Unix и Windows. Я также проверяю, не используется ли PID.

Ответы [ 11 ]

144 голосов
/ 20 февраля 2009

Отправка сигнала 0 в pid вызовет исключение OSError, если pid не запущен, и ничего не сделает в противном случае.

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
60 голосов
/ 12 июля 2013

Посмотрите на модуль psutil:

psutil (утилиты системы и процессов python) - это кроссплатформенная библиотека для получения информации о запущенных процессах и загрузка системы (ЦП, память, диски , сеть) в Python. [...] В настоящее время он поддерживает 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

Для справки:

55 голосов
/ 04 августа 2011

код mluebke не на 100% правильный; kill () также может вызывать EPERM (доступ запрещен), в этом случае это, очевидно, означает, что процесс существует. Это должно работать:

(отредактировано в соответствии с комментариями Джейсона Р. Кумбса)

import errno
import os
import sys

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
15 голосов
/ 25 января 2017

Ответы, включающие отправку «сигнала 0» процессу, будут работать , только если рассматриваемый процесс принадлежит пользователю, выполняющему тест . В противном случае вы получите OSError из-за разрешений , даже если в системе существует pid.

Чтобы обойти это ограничение, вы можете проверить, существует ли /proc/<pid>:

import os

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

Очевидно, это относится только к системам на основе Linux.

6 голосов
/ 01 мая 2014

Опираясь на 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
6 голосов
/ 25 ноября 2013

В 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
6 голосов
/ 20 февраля 2009

Смотрите здесь для оконного способа получения полного списка запущенных процессов с их идентификаторами. Это было бы что-то вроде

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.

4 голосов
/ 15 июля 2013

Объединение Ответ Джампаоло Родолы для 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 голосов
/ 21 января 2015

В 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

2 голосов
/ 27 мая 2014

Это будет работать для 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")
...