moneda - ¿Cómo verificar si existe un proceso con un pid dado en Python?
juego de dado en python (11)
¿Hay alguna manera de verificar si un pid corresponde a un proceso válido? os.getpid()
un pid de una fuente diferente que no sea de os.getpid()
y necesito verificar si un proceso con ese pid no existe en la máquina.
Necesito que esté disponible en Unix y Windows. También estoy verificando si el PID NO está en uso.
Al combinar la respuesta de Giampaolo Rodolà para POSIX y la mía para Windows , obtuve esto:
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
Busque here forma específica de Windows de obtener una lista completa de los procesos en ejecución con sus ID. Sería algo así como
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]
A continuación, puede verificar pid que obtiene en contra de esta lista. No tengo idea del costo de rendimiento, así que será mejor que lo compruebes si vas a hacer la verificación de pid a menudo.
Para * NIx, solo usa la solución de mluebke.
Echa un vistazo al módulo psutil
:
psutil (python system and process utilities) es una biblioteca multiplataforma para recuperar información sobre procesos en ejecución y utilización del sistema (CPU, memoria, discos, red) en Python. [...] Actualmente es compatible con Linux , Windows , OSX , FreeBSD y Sun Solaris , arquitecturas de 32 bits y de 64 bits , con versiones de Python de 2.6 a 3.4 (los usuarios de Python 2.4 y 2.5 pueden usar la versión 2.1.3) . PyPy también se sabe que funciona.
Tiene una función llamada pid_exists()
que puede usar para verificar si existe un proceso con el pid dado.
Aquí hay un ejemplo:
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
Para referencia:
El código mluebke no es 100% correcto. kill () también puede generar EPERM (acceso denegado), en cuyo caso eso obviamente significa que existe un proceso. Se supone que esto funciona:
(editado según los comentarios de Jason R. Coombs)
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
No puede hacer esto en Windows a menos que use pywin32, ctypes o un módulo de extensión C. Si estás de acuerdo con depender de una lib externa, puedes usar psutil :
>>> import psutil
>>> psutil.pid_exists(2353)
True
El envío de la señal 0 a un pid generará una excepción OSError si el pid no se está ejecutando, y no hará nada de lo contrario.
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
En Python 3.3+, puede usar nombres de excepción en lugar de constantes de errno. Versión de 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
En Windows, puede hacerlo de esta manera:
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
En primer lugar, en este código, intenta obtener un control para el proceso con pid dado. Si el identificador es válido, cierre el identificador del proceso y devuelva True; de lo contrario, devuelve False. Documentación para OpenProcess: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx
Esto funcionará para Linux, por ejemplo, si quieres comprobar si se está ejecutando banshee ... (banshee es un reproductor de música)
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")
Las respuestas que envían el envío de la "señal 0" al proceso funcionarán solo si el proceso en cuestión es propiedad del usuario que ejecuta la prueba . De lo contrario, obtendrá un OSError
debido a los permisos , incluso si el pid existe en el sistema.
Para omitir esta limitación, puede verificar si existe /proc/<pid>
:
import os
def is_running(pid):
if os.path.isdir(''/proc/{}''.format(pid)):
return True
return False
Sobre la base de ntrrgc''s he reforzado la versión de Windows para que compruebe el código de salida del proceso y compruebe los permisos:
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
Yo diría que use el PID para cualquier propósito que lo esté obteniendo y maneje los errores con gracia. De lo contrario, es una carrera clásica (el PID puede ser válido cuando se comprueba que es válido, pero se va un instante más tarde)