1. 课程导入与排障思维建立
Python 计算任务出问题,最让人头疼的往往不是报错本身,而是“不知道从哪里看起”。一段数据处理脚本跑了两小时没有输出、一个训练任务在第 3 个 epoch 突然内存暴涨、一个批处理作业在集群上被系统杀掉——这些现象背后可能是语法错误、资源不足、并发竞争、外部依赖超时,也可能是数据本身不符合预期。本课程用 45 个典型场景,帮助你把“凭感觉猜”变成“按证据查”。
一、计算任务异常的分类
排障的第一步是给异常“归位”。按发生层次,可以把 Python 计算任务的异常分为四类:
- 语法与导入类:代码无法被解释器接受,或模块找不到。典型如
SyntaxError、IndentationError、ModuleNotFoundError。这类问题通常在启动阶段就暴露,定位成本最低。 - 运行时逻辑类:代码能跑,但结果不对或中途崩溃。典型如
TypeError、KeyError、ValueError、ZeroDivisionError,以及数值溢出、空数组参与运算等。 - 资源与环境类:代码逻辑正确,但运行环境不满足要求。典型如内存耗尽(
MemoryError或被 OOM Killer 终止)、磁盘写满、文件句柄耗尽、GPU 显存不足、依赖版本冲突。 - 外部依赖与并发类:任务依赖的网络、数据库、消息队列、子进程或线程池出现超时、死锁、竞态。典型如
requests.Timeout、数据库连接池耗尽、multiprocessing子进程挂起。
分类的意义在于缩小搜索范围:看到 ModuleNotFoundError 就不必去查内存;看到进程被 SIGKILL 终止,就应优先怀疑资源而非语法。下面的信号链图展示了从“任务异常”到“定位到具体类别”的判断路径,以及每类问题最值得先看的证据。
二、诊断流程:从现象到根因
一个可复用的诊断流程包含五个动作,顺序可以微调,但不应跳过:
- 稳定复现:记录触发条件——输入文件、参数、Python 版本、依赖版本、运行命令。不能复现的问题,先补日志再谈定位。
- 读取证据:完整阅读 traceback 的最后一行(异常类型与消息)和倒数第二行(出错位置),不要只看第一行。对于无 traceback 的终止,检查退出码:
echo $?返回 137 通常意味着被SIGKILL终止,应查dmesg | grep -i oom。 - 缩小范围:用二分法注释代码、缩小输入规模、替换可疑依赖,把问题压缩到最小可复现片段。
- 提出假设并验证:每次只改一个变量,记录改动前后的现象差异,避免“改了三处好了但不知道哪处起作用”。
- 修复与回归:修复后补充断言或测试用例,防止同类问题再次出现。
举个具体例子。假设一个批处理脚本在处理第 5000 条记录时退出,终端只显示 Killed。按流程:先确认命令与输入可复现;再查退出码为 137;用 dmesg 看到 OOM Killer 记录了该进程;于是把假设定为“单条记录累积导致内存增长”,用 tracemalloc 在每 1000 条处打印当前内存峰值,发现某字段被不断追加进一个全局列表。修复方式是把该列表改为按批清空,并加上 gc.collect() 的时机控制。整个过程没有靠猜,每一步都有证据支撑。
三、排障工具链概览
工具不必一次学全,但要知道“什么问题该拿什么工具”。下面按用途给出最小工具集:
| 用途 | 工具 | 典型场景 |
|---|---|---|
| 异常定位 | traceback、logging.exception | 保留完整调用栈,替代 print |
| 交互调试 | pdb、breakpoint() | 在可疑行暂停,检查局部变量 |
| 性能分析 | cProfile、py-spy | 找出耗时函数、采样运行中进程 |
| 内存分析 | tracemalloc、memory_profiler | 定位内存增长点与峰值 |
| 系统观测 | psutil、top、nvidia-smi | CPU、内存、显存、句柄占用 |
| 环境核对 | pip freeze、conda list | 依赖版本冲突排查 |
建议在项目初期就统一日志格式,至少包含时间戳、级别、模块名和行号,例如使用 logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s:%(lineno)d %(message)s")。这行配置在后续几十个案例中会反复体现价值。
四、学习路径说明
本课程按“先分类、再工具、后场景”的顺序推进。前半部分聚焦语法与运行时错误,帮助你建立读 traceback 的肌肉记忆;中段进入资源与环境问题,涉及内存、磁盘、并发与依赖;后段覆盖外部服务、分布式任务与生产环境排障。每个案例都遵循“现象描述—证据采集—根因分析—修复验证”的闭环,你可以把它当作排障手册,也可以按顺序系统学习。
最后强调一种心态:异常不是敌人,而是系统给出的线索。把每次排障当作一次对程序运行机制的理解,积累下来的不只是修复技巧,更是对 Python 计算任务整体行为的判断力。