python多进程debug

news/2024/10/3 19:11:46

代码调试

问题阐述

最近遇到一个python debug多进程的问题

有一个进程A,这个进程会fork出8个进程B,fork join结束后,又会fork出8个进程A。

假设按时间有序,我就只想断fork出的第一个B和第一个进程A,怎么做?(breakpoint just break only once)

类似于java多线程调试的意思,只断一个线程,all->thread,make default

断点命中时不会阻塞其他进程

https://blog.csdn.net/u011781521/article/details/79251819

主要几个问题点

  • 多个进程会同时刷log,特别乱,没办法过滤(加pid过滤,还算好解决)
  • 使用pdb断点时,会同时block所有其他进程

调试主流方式

首先python主流有两类debug方式

第一类是通过ide,比如vscode、pycharm。

比较无脑、界面化的操作方式,但缺点也很明显,很依赖一个可以控制的函数入口(例如main,ut入口)。

第二类是通过pdb,在相关代码片段中加breakpoint语句,等进程执行时自动触发断点,进行拦截。

适合一些比较复杂的进程衍生模式,不太依赖特定的函数入口。这种相对来说更精确一点,对依赖外部环境依赖小。

需要对pdb、gdb类似的东西有一定的了解。其次,多进程下并不太友好;pdb本身功能过于单一。

找了一下pdb的平替有pdb++、ipdb、rpdb。

rpdb就是remote,前两个其实差不多,但是pdb的好处是,基本你不需要去改原来的pdb断点,开箱即用。

pdb++还有啥好处见引文,但是还是存在多进程不友好的问题,会多次触发断点,一个命令语句会有较多的副作用,尤其在Smart command parsing加持下,基本就是不可调试的状态。

TL; DR

pdbpp(又称 pdb++)是 Python 标准调试器 pdb 的一个增强版本,为调试体验提供了许多改进和新功能。在功能上,它完全向后兼容 pdb,但增加了许多便利的特性,简化了调试过程。以下是 pdbpp 相比于 pdb 提供的主要增强功能:

1. 彩色语法高亮(Syntax Highlighting)

pdbpp 使用 pygments 库为代码和输出提供彩色语法高亮显示,使得调试器输出更加易读,特别是在查看复杂表达式和代码块时。变量名、关键字、字符串、数字等会有不同的颜色,帮助用户快速定位信息。

  • pdb:没有颜色,输出是纯文本。
  • pdbpp:提供语法高亮,颜色区分不同类型的内容。

2. 更强大的自动补全(Tab Completion)

pdbpp 中,按下 Tab 键可以自动补全变量名、函数名、类名等,类似于现代 IDE 中的补全功能。这大大提高了调试时的效率,特别是在处理复杂的对象或长命名时。

  • pdb:有限的自动补全功能。
  • pdbpp:增强的自动补全,支持更多命令、变量、对象属性和方法。

3. 可配置的显示选项(Sticky Mode)

pdbpp 提供一个非常强大的 "sticky mode",它可以在调试过程中始终显示当前代码的上下文。每次执行下一步时,pdbpp 会自动刷新并显示当前代码段的最新状态,而不需要手动查看代码上下文。

  • pdb:手动使用 listlonglist 查看代码上下文。
  • pdbppsticky mode 持续显示代码上下文,用户更容易跟踪执行的代码。

4. 更智能的调试命令

pdbpp 增强了原始 pdb 的一些常用命令,并增加了新的命令:

  • interact:允许你在调试器中启动一个交互式 Python shell,直接操作调试时的上下文和变量。
  • longlist (ll):显示当前函数的完整代码,而不仅仅是当前行的上下文。
  • sticky:启用或禁用 sticky mode,在该模式下会持续显示代码的上下文。
  • track:跟踪异常,并显示其完整的追溯信息。
  • source:查看某个函数或方法的完整源代码。

5. 更灵活的配置和扩展

pdbpp 提供了更多的配置选项,允许你通过 .pdbrc 文件自定义调试器的行为,例如颜色、补全方式、命令别名等。

  • pdb:有限的配置选项。
  • pdbpp:支持用户自定义配置文件,灵活设置调试器的行为。

6. 更好的 Python 3 支持

pdbpp 针对 Python 3 做了更多优化,支持 Python 3 的新语法和特性,如 asyncawait,并能更好地处理 Python 3 中的一些新特性。

7. 友好的错误信息

pdbpp 提供了更加直观的错误信息格式,增强了显示异常和回溯的方式,使调试复杂的错误更加容易。

8. 可自定义的调试器提示符

你可以通过 pdbpp 自定义调试器的提示符(prompt)。这对某些开发者来说是个很方便的功能,特别是当你在长时间调试时,能够清楚知道当前的调试状态。

9. 显示变量值的悬停功能

当你在 pdbpp 中查看代码时,悬停在变量上会显示其当前的值。这对于快速查看变量的状态非常有用,无需输入变量名来查看当前值。


小结

pdbpppdb 的一个增强版本,带来了彩色高亮、自动补全、sticky mode、自定义配置等功能,大大提升了调试体验。如果你经常使用 pdb 进行调试,pdbpp 将让你的调试过程更高效、愉快。

问题场景

现在我往我关心的代码里,加入了断点import pdb; pdb.set_trace()但是他连续触发了8次,导致我没办法继续调试了,怎么办?

按了一次c直接所有其他进程都相应,我有没有办法只断某一个进程(随便哪个)?

比较直觉的会想到条件断点,但是触发条件的唯一值有哪些呢?

方案思路

天然唯一值,比如pid、ppid、deviceid、特定配置参数,process相关参数,持有的一些特殊资源(fd描述符)。

非天然唯一值,比如特定环境变量。

也可以考虑锁,谁先抢占到锁,谁就一直持有这把锁(至少能保证只有一个进程断到),这个可以往一个特定文件写入pid实现。封装一个get函数,这个函数尝试读取一个文件,如果这个文件不存在,先创建并写入当前的进程id,再返回该id,如果这个文件存在,直接返回文件内容转成int,上层只需要比较id和自身os.getpid()的一致性。

方案细节

方案A 判断ppid

由于最开始只有一个父进程,所以用他作为ppid去判定。然而并不正确,子进程fork了8个,8个同时命中无效。

方案B 判断pid

pid对10取余,用一个magic number(比如0),判断相等性,进行断点。

(有效且粗暴的方式,但具有一定随机性。这块是由于进程pid的分配算法,进程pid并不一定具有连续性,并且有一定随机性,有可能出现无法命中或者多次命中的概率。)

方案C 父进程传变量给子进程

只需要在子进程fork一开始传入一个唯一值即可,这里用到了环境变量。

首先最开始的父进程A进程是一个前台进程,ctrl+c打断时,会触发一些multiprocessing和task相关的堆栈,其实可能A在执行过程中fork了其他所有进程(事实上并不对)。

尝试检索了一下相关库,检索multiprocessing关键字,确实能找到一句

ctx = multiprocessing.get_context("spawn") 
...
for i in range(5):item = ctx.Process(...)item.start()
...

尝试在loop中,先设置os.environ['DEBUG']=i,fork出来的子进程会继承(unix机制,子进程会继承父进程的一些属性)环境变量,尝试用该环境变量做判断,发现断点断不上,这个方案是有问题的。

原因是父进程A fork出了8个B,我们关心的断点其实在B的进程中,fork完8个B进程,父进程A完成join,继续开始fork8个A子进程,理论上这些断点会生效,但是我们miss掉了断点出现的时机。

方案D 父进程B读取一些特定配置值(比如deviceid 0-8)做判断

D.A 尝试读取一个config值里的特定字段,但发现这个config是动态生成的,他也不是一个单例(python中的单例不太一样,强行弄意义不大),并且这个值加载的时机不明确,所以不能用

D.B 尝试获取该进程持有的一些资源、文件描述符(如/dev/xxx),感觉有点麻烦,但是理论上是可行的

D.C 通过ps -ef观察,其实进程B在启动时有一些特定的唯一值入参,进程的启动命令大概长process_b device_id 8 deivce_id xxxx,能明显看出,第二个参数就是我们需要的唯一值。

尝试通过sys.argv获取第一个参数,直接判断。发现sys.argv竟然是空的,那么这些参数来自哪里呢?

只有通过python命令行启动的进程,才会有sys.argv,如果不是这种方式,比如用c启动的命令行,他就不会有这个参数。

那如何获取这个参数?

两种方式,第一种取读取/proc/{pid}/cmdline下的一些属性,找到这个值,第二种

import psutil
p = psutil.Process()
cmdline = p.cmdline()

采用了第二种方式,再pdb++获取了cmdline[1],并且和'1'比较测试了一下,是成功的。至此,完成了条件断点。

小结

  1. 要注意观察进程的创建方式和创建的流程(ps -ef, pstree)
  2. 明确需要断点问题的界限
  3. 寻找一切与问题相关的上下文,尽可能将问题缩小在一个区间

TL;DR

代码阅读&修改

container内python代码调试

现在的ide普遍都支持ssh连接,理论上只要配置好了ssh服务,就可以直接连container,直接对container内的代码进行调试。(直接用开发机的开发机环境是最好的,代码可以随意点,都不会报错和飘红

ssh

安装ssh服务(能用apt直接安的可以省这一步)

  1. 从网站随意下一下源码包

https://www.openssh.com/portable.html

  1. 解压进入到代码目录
  2. ./configure 生成编译需要的配置文件
  3. make $(nproc) 编译
  4. make install 安装

配置

vim /etc/sshd/sshd_config

PermitRootLogin改成yes,password-auth也改成yes,端口随便换一个,不要和宿主机撞

启动

service ssh start(这块不能用systemctl)

宿主机要把docker这个端口主动的暴露出去(这个在启动的时候就要完成)

pycharm ssh配置连接

包太大,下载不了的问题参考

https://blog.csdn.net/qq_42534403/article/details/135969955

连接完效果大概像

基本和本地开发效果一致,比较恼火的是,他有时候不会保存项目打开前后的上下文,可能你做的一些mark或者pin都会丢失。

如果对library进行调试,额外注意需要标注

pdb++ cheatsheet (via gpt4)

个人感觉比较好用的就是ll pp sticky,最好禁用Smart command parsing(真是自作聪明的行为),基本用着和解释性语言的感觉差不多,像是直接在python中运行一样

下面是一个方便参考的 pdb++ 调试命令 Cheatsheet,它包含了 pdb++ 中常用的调试命令以及增强功能,帮助你快速上手调试。


pdb++ Cheatsheet

基本命令

命令 说明
h/help 显示帮助信息,输入 help <command> 查看某个命令的详细帮助。
n/next 执行下一行代码,跳过函数调用。
s/step 进入下一行代码,如果是函数调用,则进入函数内部。
r/return 执行到当前函数的返回处。
c/continue 继续执行程序,直到遇到下一个断点。
q/quit 退出调试器,终止程序。
l/list 显示当前代码的上下文(默认 11 行),可指定范围,如 list 10, 20
ll/longlist 显示当前函数的完整代码。
p/print 打印表达式的值,例如 p my_var
pp 使用漂亮的格式(pretty print)打印表达式的值。
w/where 显示当前的调用栈信息。
bt where,显示完整的回溯信息。
up/u 移动到上一层调用栈。
down/d 移动到下一层调用栈。

断点管理

命令 说明
b/break 设置断点。用法:break <lineno>break <filename>:<lineno>
tbreak 设置临时断点,命中一次后自动删除。
cl/clear 清除所有断点。
disable 禁用断点。
enable 启用断点。
ignore 忽略断点,指定命中多少次后才激活。
condition 为断点设置条件。例如:condition 1 x > 10

变量和表达式

命令 说明
p/print 打印表达式的值,例如 p my_var
pp 使用漂亮的格式(pretty print)打印表达式的值。
whatis 显示表达式的类型,例如 whatis my_var
display 每次停止时自动显示一个表达式的值,例如 display my_var
undisplay 取消显示某个表达式的值。
a/args 打印当前函数的参数及其值。
retval 显示最后一个返回值。
locals() 查看当前作用域中的局部变量。
globals() 查看全局变量。

代码执行

命令 说明
! 执行 Python 表达式。例如 !my_var = 5
interact 启动一个交互式 Python shell,可以在当前上下文中执行任意代码。
run 重新运行脚本。例如:run arg1 arg2

特殊功能

命令 说明
sticky 启用/禁用 粘性模式,在调试时持续显示代码上下文。
source 显示某个函数或类的源代码,例如 source my_function
track 跟踪异常,显示其完整的追溯信息。
display 在每次停止时自动显示指定的变量值。
undisplay 停止自动显示变量值。

粘性模式(Sticky Mode)

sticky 模式是 pdb++ 中的一个特殊功能,它会在调试时持续显示当前代码的上下文。每次程序执行到下一行,pdb++ 会自动刷新并显示当前位置的代码片段。

  • 启用/禁用

    • 输入 sticky 切换模式。
  • 使用场景

    • 在调试过程中,sticky 模式可以帮助你持续观察代码的变化,无需手动调用 list 命令。

命令别名

pdb++ 允许你为常用命令创建别名,简化调试过程。例如,你可以为 longlist 创建一个别名 ll

alias ll longlist

你也可以在 .pdbrc.py 文件中配置这些别名,以便每次启动 pdb++ 时自动加载。


自定义配置

你可以通过 ~/.pdbrc.py 文件自定义 pdb++ 的行为,例如自动启用语法高亮、粘性模式、设置别名等。

示例 .pdbrc.py 文件:

# ~/.pdbrc.py# 自动启用粘性模式
def setup(self):self.sticky = True# 设置别名
alias ll longlist
alias n next
alias s step
alias c continue

调试快捷键

快捷键 说明
Ctrl + D 退出调试器。
Ctrl + L 清屏。
Tab 自动补全命令、变量、函数名等。

常用调试工作流

  1. 启动调试:在代码中插入 import pdb; pdb.set_trace(),或者运行脚本时通过 python -m pdb your_script.py 进入调试模式。
  2. 设置断点:用 break <lineno>tbreak 设置断点。
  3. 逐步调试:使用 nextstep 逐行执行代码,检查变量的值。
  4. 检查变量:通过 ppp 打印变量的值,使用 whatis 查看变量的类型。
  5. 跟踪异常:使用 track 追踪异常的完整回溯信息。
  6. 使用粘性模式:通过 sticky 持续显示代码的上下文,实时跟踪代码执行。

结语

pdb++ 是一个强大且灵活的调试工具,它在 pdb 的基础上提供了许多增强功能,使调试过程更加高效、直观。通过这份 Cheatsheet,你可以快速掌握 pdb++ 的常用命令并提升调试效率。

pdb(pdb++)方法

下面是你列出的 pdb++(和 pdb)中常用函数的详细讲解,包括各个函数的签名、参数说明、用法以及它们的具体作用。在 pdb++ 中,这些函数提供了灵活的调试能力,可以根据具体需求使用不同的调试方法。


1. pdb.run(statement, globals=None, locals=None)

作用

  • 在调试器中执行一条 Python 语句(类似于 exec() 函数),并在执行该语句时进入调试模式。

签名

def run(statement: str, globals: dict[str, Any] | None = None, locals: Mapping[str, Any] | None = None) -> None

参数

  • statement: 一个字符串类型的 Python 语句,表示你想要执行的代码。
  • globals: 可选参数,表示全局命名空间的字典。如果不提供,默认为 None,使用当前的全局命名空间。
  • locals: 可选参数,表示局部命名空间的映射。如果不提供,默认为 None,使用当前的局部命名空间。

用法

import pdbstatement = 'x = 10; y = 20; z = x + y'
pdb.run(statement)

说明

  • pdb.run() 类似于 exec(),但在执行过程中启动调试器,方便你调试一段代码的执行过程。

2. pdb.runeval(expression, globals=None, locals=None)

作用

  • 在调试器中求值一个表达式(类似于 eval() 函数),并返回其结果。这个函数允许你在调试模式下执行表达式并获取结果。

签名

def runeval(expression: str, globals: dict[str, Any] | None = None, locals: Mapping[str, Any] | None = None) -> Any

参数

  • expression: 一个字符串类型的 Python 表达式,表示你想要计算的表达式。
  • globals: 可选参数,表示全局命名空间的字典。如果不提供,默认为 None,使用当前的全局命名空间。
  • locals: 可选参数,表示局部命名空间的映射。如果不提供,默认为 None,使用当前的局部命名空间。

用法

import pdbexpression = '10 + 20'
result = pdb.runeval(expression)
print(result)

说明

  • pdb.runeval() 类似于 eval(),但在调试器运行环境中执行表达式,并返回计算结果。

3. pdb.runctx(statement, globals, locals)

作用

  • 在调试器中执行一条 Python 语句,并显式传递全局和局部命名空间。这与 pdb.run() 类似,但强制要求提供 globalslocals 参数。

签名

def runctx(statement: str, globals: dict[str, Any], locals: Mapping[str, Any]) -> None

参数

  • statement: 需要执行的 Python 语句。
  • globals: 全局命名空间的字典。
  • locals: 局部命名空间的映射。

用法

import pdbglobals = {'a': 10}
locals = {'b': 20}
statement = 'c = a + b'
pdb.runctx(statement, globals, locals)
print(globals, locals)

说明

  • pdb.runctx() 允许你使用自定义的命名空间执行代码,这在调试复杂的上下文时非常有用。

4. pdb.runcall(func, *args, **kwds)

作用

  • 在调试器中调用一个函数,并传递参数。这允许你在调试模式下运行函数并检查其执行过程。

签名

def runcall(func: Callable[_P, _T], *args: _P.args, **kwds: _P.kwargs) -> _T | None

参数

  • func: 要调用的函数。
  • *args: 传递给函数的参数。
  • **kwds: 传递给函数的关键字参数。

用法

import pdbdef divide(a, b):return a / bresult = pdb.runcall(divide, 10, 2)  # 调试 divide(10, 2)
print(result)

说明

  • pdb.runcall() 允许你在调试器中运行某些函数,并检查函数执行的每一步。这在调试有参数的函数时非常有用。

5. pdb.set_trace()

作用

  • 手动在代码中设置一个断点,启动调试器并暂停程序执行。

签名

def set_trace(*, header: str | None = None) -> None

参数

  • header: 可选参数,类型为 str | None,表示当调试器启动时输出的自定义消息。如果不提供,默认为 None

用法

import pdbdef my_function():x = 10pdb.set_trace(header="调试器启动")  # 在这里进入调试模式,显示自定义消息y = 20z = x + yprint(z)my_function()

说明

  • pdb.set_trace() 是手动调试的常用工具,它允许你在代码执行到某个位置时暂停,并进入调试模式。header 参数可以提供额外的信息,以便在调试器启动时显示。

6. pdb.post_mortem()

作用

  • 在异常发生后启动调试器,允许你查看异常发生时的上下文。这在调试未捕获的错误时非常有用。

签名

def post_mortem(t: TracebackType | None = None) -> None

参数

  • t: 可选参数,类型为 TracebackType | None,表示要调试的回溯对象。如果不提供,使用最近的异常回溯。

用法

import pdbdef divide(a, b):return a / btry:divide(1, 0)
except ZeroDivisionError:pdb.post_mortem()  # 在异常发生后进入调试模式

说明

  • post_mortem() 允许你在异常发生后进入调试器,并检查导致异常的上下文。在调试程序崩溃时非常有用。

7. pdb.pm()

作用

  • 立即进入调试模式,调试最近的未捕获异常。它是 post_mortem() 函数的快捷方式。

签名

def pm() -> None

参数

  • 无参数。

用法

import pdbdef divide(a, b):return a / btry:divide(1, 0)
except:pdb.pm()  # 调试最近的未捕获异常

说明

  • pm()post_mortem() 的简化版本,自动处理最近发生的异常并启动调试器。它适合快速进入调试模式,而无需显式捕获异常。

总结

  • run(): 在调试模式下执行一条 Python 语句。
  • runeval(): 在调试模式下求值一个表达式并返回结果。
  • runctx(): 在调试模式下执行一条 Python 语句,并使用自定义的全局和局部命名空间。
  • runcall(): 通过调试器调用一个函数,并传递参数。
  • set_trace(): 手动设置断点,进入调试模式。
  • post_mortem(): 在异常发生后进入调试模式。
  • pm(): 调试最近的未捕获异常,是 post_mortem() 的快捷方式。

这些函数提供了灵活的调试工具集,适合不同的调试需求。

python debug相关环境变量

在 Python 中,调试器(如 pdbpdb++)可以通过一些环境变量进行配置和控制。这些环境变量可以影响调试器的行为、设置以及输出。以下是与 Python 调试相关的主要环境变量:


1. PYTHONBREAKPOINT

  • 作用:控制程序中断点的行为,特别是用于设置或禁用调试器。

  • 用法

    • 默认值PYTHONBREAKPOINT=pdb.set_trace
    • 禁用断点:将变量设置为 0,所有的 breakpoint() 调用将被忽略。
    • 自定义行为:你可以将其设置为任意可调用的调试函数,甚至是自定义函数。
  • 示例

    export PYTHONBREAKPOINT=0  # 禁用所有断点
    export PYTHONBREAKPOINT=my_debugger.set_trace  # 使用自定义调试器
    
  • 说明

    • 在 Python 3.7+ 中,breakpoint() 是用于手动进入调试的内置函数。通过设置 PYTHONBREAKPOINT,你可以更改 breakpoint() 的行为。
    • 如果设置为 0,则调试功能被禁用,即所有 breakpoint() 调用将被忽略。

2. PYTHONWARNINGS

  • 作用:控制 Python 警告的显示方式,通常用于调试时查看潜在问题。

  • 用法

    • 默认值:Python 默认只显示一次警告。
    • 可以设置成 error 来将警告变为异常,这样在调试器中可以捕获并调试警告。
  • 格式PYTHONWARNINGS=action:message:category:module:line(其中,action 是最常用的部分)

  • 常见值

    • default:默认行为,显示一次警告。
    • always:总是显示警告。
    • ignore:忽略警告。
    • error:将警告转换为异常。
    • module:每个模块显示一次警告。
    • once:仅显示一次警告。
  • 示例

    export PYTHONWARNINGS="error"  # 将所有警告视为错误
    export PYTHONWARNINGS="always"  # 总是显示所有警告
    
  • 说明

    • 当你设置 PYTHONWARNINGS="error" 时,所有 Python 警告将作为异常抛出,这样你可以在调试器中捕获它们并查看具体的堆栈信息。
    • 这在调试潜在的代码问题或需要严格处理警告时非常有用。

3. PYTHONTRACEMALLOC

  • 作用:启用或禁用内存分配跟踪,用于调试内存泄漏问题。

  • 用法

    • 默认值:未启用。
    • 设置为正整数值来控制分配追踪的深度。
  • 示例

    export PYTHONTRACEMALLOC=1  # 启用内存分配跟踪,深度为 1
    export PYTHONTRACEMALLOC=5  # 启用内存分配跟踪,深度为 5
    
  • 说明

    • 启用内存跟踪后,Python 将记录内存分配的堆栈信息。这对于调试内存泄漏或定位高内存使用问题非常有帮助。
    • 你可以使用 tracemalloc 模块来获取和显示内存分配的相关信息。

4. PYTHONDEBUG

  • 作用:启用 Python 解释器的调试输出,由解释器在启动时使用。

  • 用法

    • 设置为任意非空值时,启用调试模式(解释器的调试信息将输出到标准错误流)。
  • 示例

    export PYTHONDEBUG=1  # 启用解释器的调试模式
    
  • 说明

    • 启用 PYTHONDEBUG 后,Python 会输出更多的调试信息,包括一些内部机制的输出内容。这对于调试 Python 解释器本身或者查看解释器的详细运行信息非常有用。

5. PYTHONVERBOSE

  • 作用:启用详细输出模式,用于显示 Python 解释器加载模块的详细信息,适合调试模块导入问题。

  • 用法

    • 设置为任意非空值时,启用详细模式。
  • 示例

    export PYTHONVERBOSE=1  # 启用详细输出模式
    
  • 说明

    • 启用 PYTHONVERBOSE 后,Python 会在程序执行过程中输出每个模块导入的详细信息。这对调试模块导入路径、导入冲突或未找到模块的问题非常有帮助。

6. PYTHONMALLOC

  • 作用:控制 Python 的内存分配器类型,用于调试内存分配和内存问题。

  • 可选值

    • malloc:使用系统的 malloc()
    • pymalloc:使用 Python 的小对象分配器(默认)。
    • debug:使用 Python 的小对象分配器,并启用内存调试。
  • 示例

    export PYTHONMALLOC=debug  # 启用内存调试
    
  • 说明

    • 设置为 debug 时,Python 会启用内存分配调试机制,帮助你发现内存分配错误或内存泄漏问题。

7. PYTHONFAULTHANDLER

  • 作用:启用 Python 的故障处理程序,使得 Python 在崩溃时打印出详细的堆栈信息。

  • 用法

    • 设置为任意非空值,启用故障处理程序。
  • 示例

    export PYTHONFAULTHANDLER=1  # 启用故障处理程序
    
  • 说明

    • 启用 PYTHONFAULTHANDLER 后,当 Python 崩溃时,它会打印出 Python 错误堆栈信息,帮助你更容易地定位问题。特别是在调试 C 扩展模块或者解释器崩溃时非常有用。

8. PYTHONHASHSEED

  • 作用:控制字符串和其他哈希种子的初始化值。

  • 用法

    • 设置为一个整数值,用于确定 Python 的哈希种子。
    • 随机哈希种子默认用于防止哈希冲突攻击,但在某些情况下(如调试或测试),你可能希望使用固定值。
  • 示例

    export PYTHONHASHSEED=42  # 使用固定的哈希种子
    
  • 说明

    • 在调试涉及哈希的代码(如字典、集合)时,使用固定的哈希种子可以帮助你复现和调试某些哈希相关的错误。

9. PYTHONINSPECT

  • 作用:在程序运行结束后自动进入交互模式(REPL),可用于调试。

  • 用法

    • 设置为任意非空值时,程序运行结束后进入交互模式。
  • 示例

    export PYTHONINSPECT=1  # 程序结束后进入交互模式
    
  • 说明

    • 启用 PYTHONINSPECT 后,当 Python 程序执行结束时,它会启动交互式解释器(REPL)。这在你想要在程序结束后进一步检查状态时非常有用。

总结

以下是常见的与 Python 调试相关的环境变量:

  • PYTHONBREAKPOINT:控制 breakpoint() 的行为。
  • PYTHONWARNINGS:控制警告的处理方式。
  • PYTHONTRACEMALLOC:启用内存分配跟踪。
  • PYTHONDEBUG:启用解释器调试模式。
  • PYTHONVERBOSE:启用详细输出模式,调试模块导入问题。
  • PYTHONMALLOC:控制 Python 的内存分配器。
  • PYTHONFAULTHANDLER:启用故障处理程序,捕获崩溃时的堆栈信息。
  • PYTHONHASHSEED:设置固定的哈希种子,调试哈希相关问题。
  • PYTHONINSPECT:程序执行结束后进入交互模式。

这些环境变量为开发者提供了灵活的调试选项,适用于不同的调试场景和调试需求。

注意breakpoint()set_trace()有一些细小差别。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/67441.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

一些数学知识题

欧几里得算法费马小定理 当a,p都是是质数时,a^(p-1)=1(mod p) 证明: 举个例子 a=2,p=5; 1,2,3,4 集合(1) {1,2,3,4...,(p-1)} 2,4,6,8 => %5 => 2,4,1,3 集合(2) {1a%p,2a%p,3a%p,4a%p...,(p-1)a%p} 我们发现{1,2,3,4}和{2,4,1,3}只是…

题解:洛谷P2339 [USACO04OPEN] Turning in Homework G

题目链接:洛谷P2339 [USACO04OPEN] Turning in Homework G 首先我们考虑如何处理到达给定时间后才能交作业这一限制。其实在生活中,我们一般只会考虑什么时候交作业截止 (除了某些卷王),这样我们只用考虑如何在最大结束时间之前交作业,而不是在所有作业都没开始交之前考虑…

独立站如何批量查收录,教你独立站如何批量查收录的简单方法

独立站批量查收录是提升网站SEO效果的重要步骤。以下提供几种简单且实用的方法,帮助你高效地批量查询独立站的收录情况: 一、使用搜索引擎的Site指令结合自动化脚本 了解Site指令: 在搜索引擎(如谷歌)的搜索框中输入“site:域名”(替换为你的实际域名),执行搜索后,可以…

谷歌收录查询工具,告诉你谷歌收录查询工具使用指南

谷歌收录查询工具是网站管理员和SEO专家用于监控和管理网站在谷歌搜索结果中表现的重要工具。以下是一份详细的谷歌收录查询工具使用指南,旨在帮助你更好地了解和使用这些工具。 一、Google Search Console(谷歌搜索控制台) Google Search Console是谷歌官方提供的免费工具,…

『模拟赛』多校A层冲刺NOIP2024模拟赛01

『模拟赛记录』多校A层冲刺NOIP2024模拟赛01Rank 打得还可以总A. 构造字符串 签,但是挂了 40pts。 发现判条件只有相等和不相等,于是想到并查集维护连通块,将强制相同的两个位置的连通块合并,强制不同的先记下,最后统一判断。 重点在细节处理,合并连通块时要将位置靠后的…

虚拟机类加载机制

1. 类加载时机 一个类型(接口/类)从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将历加载、验证、准备、解析、初始化、使用和卸载七个阶段,其中验证、准备、解析三个部分统称为连接(Linking)。 加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,…

CSS display属性 inline-block flex grid

CSS display inline-block flex grid ======================================= CSS的display属性是一个核心属性,用于控制元素如何在页面布局中显示,包括其盒模型的行为。以下是display属性的一些常见值及其示例代码:1. block 说明:将元素变为块级元素,独占一行,可以…

[39] (多校联训) A层冲刺NOIP2024模拟赛01

你们不感觉最近机房网越来越慢了吗,现在下个 10M 的东西要用三分钟,而且期间访问不了网站 整个机房分 1000Mbps 的带宽为啥只能分这么一点, huge 拿我电脑挖矿了? 本来以为多校就是多校的,结果是真的多校,一百一十多个人在一块考 huge: 参加的都是咱们北方这几个强校 你说…