set_start_method - ¿Cómo adjuntar el depurador a un subproceso python?
python pool process (6)
Necesito depurar un proceso hijo generado por multiprocessing.Process()
. El pdb
pdb parece no ser consciente de forking y no puede adjuntarse a procesos ya en ejecución.
¿Hay algún depurador de Python más inteligente que pueda asociarse a un subproceso?
Esta es una elaboración de la respuesta de Romuald que restaura la entrada original usando su descriptor de archivo. Esto mantiene la línea de lectura trabajando dentro del depurador. Además, la gestión especial de pdb de KeyboardInterrupt está deshabilitada, para no interferir con el manipulador sigint de multiprocesamiento.
class ForkablePdb(pdb.Pdb):
_original_stdin_fd = sys.stdin.fileno()
_original_stdin = None
def __init__(self):
pdb.Pdb.__init__(self, nosigint=True)
def _cmdloop(self):
current_stdin = sys.stdin
try:
if not self._original_stdin:
self._original_stdin = os.fdopen(self._original_stdin_fd)
sys.stdin = self._original_stdin
self.cmdloop()
finally:
sys.stdin = current_stdin
He estado buscando una solución simple para este problema y se me ocurrió esto:
import sys
import pdb
class ForkedPdb(pdb.Pdb):
"""A Pdb subclass that may be used
from a forked multiprocessing child
"""
def interaction(self, *args, **kwargs):
_stdin = sys.stdin
try:
sys.stdin = open(''/dev/stdin'')
pdb.Pdb.interaction(self, *args, **kwargs)
finally:
sys.stdin = _stdin
Úsalo de la misma manera que podrías usar el Pdb clásico:
ForkedPdb().set_trace()
Si está en una plataforma compatible, pruebe DTrace . La mayor parte de la familia BSD / Solaris / OS X es compatible con DTrace.
Aquí hay una introducción del autor . Puedes usar Dtrace para depurar casi cualquier cosa.
Aquí hay una publicación SO sobre el aprendizaje de DTrace.
Sobre la base de la idea de @memplex, tuve que modificarla para que funcionara con joblib
estableciendo sys.stdin
en el constructor, así como pasándolo directamente a través de joblib.
<!-- language: lang-py -->
import os
import pdb
import signal
import sys
import joblib
_original_stdin_fd = None
class ForkablePdb(pdb.Pdb):
_original_stdin = None
_original_pid = os.getpid()
def __init__(self):
pdb.Pdb.__init__(self)
if self._original_pid != os.getpid():
if _original_stdin_fd is None:
raise Exception("Must set ForkablePdb._original_stdin_fd to stdin fileno")
self.current_stdin = sys.stdin
if not self._original_stdin:
self._original_stdin = os.fdopen(_original_stdin_fd)
sys.stdin = self._original_stdin
def _cmdloop(self):
try:
self.cmdloop()
finally:
sys.stdin = self.current_stdin
def handle_pdb(sig, frame):
ForkablePdb().set_trace(frame)
def test(i, fileno):
global _original_stdin_fd
_original_stdin_fd = fileno
while True:
pass
if __name__ == ''__main__'':
print "PID: %d" % os.getpid()
signal.signal(signal.SIGUSR2, handle_pdb)
ForkablePdb().set_trace()
fileno = sys.stdin.fileno()
joblib.Parallel(n_jobs=2)(joblib.delayed(test)(i, fileno) for i in range(10))
Una idea que tuve fue crear clases "ficticias" para falsificar la implementación de los métodos que está utilizando desde el multiprocesamiento:
from multiprocessing import Pool
class DummyPool():
@staticmethod
def apply_async(func, args, kwds):
return DummyApplyResult(func(*args, **kwds))
def close(self): pass
def join(self): pass
class DummyApplyResult():
def __init__(self, result):
self.result = result
def get(self):
return self.result
def foo(a, b, switch):
# set trace when DummyPool is used
# import ipdb; ipdb.set_trace()
if switch:
return b - a
else:
return a - b
if __name__ == ''__main__'':
xml = etree.parse(''C:/Users/anmendoza/Downloads/jim - 8.1/running-config.xml'')
pool = DummyPool() # switch between Pool() and DummyPool() here
results = []
results.append(pool.apply_async(foo, args=(1, 100), kwds={''switch'': True}))
pool.close()
pool.join()
results[0].get()
Winpdb es prácticamente la definición de un depurador de Python más inteligente. Es explícitamente compatible con bajar un fork , no estoy seguro de que funcione bien con multiprocessing.Process()
pero vale la pena intentarlo.
Para obtener una lista de candidatos para verificar el soporte de su caso de uso, consulte la lista de Depuradores de Python en la wiki.