![](/img/trans.png)
[英]Pycharm: How to use the green “Attach Debugger” button in python console
[英]How to attach debugger to a python subproccess?
我需要調試由multiprocessing.Process()
產生的子進程。 pdb
degugger 似乎不知道分叉並且無法附加到已經運行的進程。
是否有任何更智能的 python 調試器可以附加到子進程?
我一直在尋找一個簡單的解決方案來解決這個問題並想出了這個:
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
像使用經典 Pdb 一樣使用它:
ForkedPdb().set_trace()
Winpdb幾乎是更智能的 Python 調試器的定義。 它明確支持下叉,不確定它是否與multiprocessing.Process()
一起工作,但值得一試。
有關檢查是否支持您的用例的候選列表,請參閱 wiki 中的Python 調試器列表。
這是 Romuald 的答案的詳細說明,它使用其文件描述符恢復原始標准輸入。 這使 readline 在調試器中工作。 此外,pdb 對 KeyboardInterrupt 的特殊管理被禁用,以免干擾多處理 sigint 處理程序。
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
基於@memplex 的想法,我必須通過在構造函數中設置sys.stdin
以及通過 joblib 直接傳遞它來修改它以使其與joblib
一起使用。
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))
remote-pdb可用於調試子進程。 安裝后,在需要調試的代碼中加入以下幾行:
import remote_pdb
remote_pdb.set_trace()
remote-pdb 將打印一個端口號,該端口號將接受用於調試該特定進程的 telnet 連接。 關於 worker 啟動順序有一些注意事項,在使用各種前端時 stdout 的位置等。為了確保使用特定端口(必須是免費的並且當前用戶可以訪問),請改用以下命令:
from remote_pdb import RemotePdb
RemotePdb('127.0.0.1', 4444).set_trace()
remote-pdb 也可以通過 Python 3.7 中的breakpoint()
命令啟動。
我的一個想法是創建“虛擬”類來偽造您從多處理中使用的方法的實現:
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()
這是 ForkedPdb(Romuald 的解決方案)的版本,它適用於基於 Windows 和 *nix 的系統。
import sys
import pdb
import win32console
class MyHandle():
def __init__(self):
self.screenBuffer = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
def readline(self):
return self.screenBuffer.ReadConsole(1000)
class ForkedPdb(pdb.Pdb):
def interaction(self, *args, **kwargs):
_stdin = sys.stdin
try:
if sys.platform == "win32":
sys.stdin = MyHandle()
else:
sys.stdin = open('/dev/stdin')
pdb.Pdb.interaction(self, *args, **kwargs)
finally:
sys.stdin = _stdin
只需使用PuDB 即可為您提供出色的 TUI(終端上的 GUI)並支持多處理,如下所示:
from pudb import forked; forked.set_trace()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.