用 strategy.matrix 配合 include 显式定义合法组合,控制 job 数量在 6 个以内,按 python 版本分组管理依赖文件,将耗时操作移出矩阵,避免笛卡尔积导致超时或并发限流。

矩阵测试在 gitHub Actions 中怎么写才不爆炸
直接说结论:用 strategy.matrix 配合 include 或 exclude 控制组合,别硬套 Python 版本+依赖版本的笛卡尔积——多数项目根本不需要全量交叉,反而会触发超时或并发限制。
常见错误是照抄官方示例,把 python-version 和 dependency-version 全扔进 matrix,结果跑出 12 个 job,其中 8 个因 pip install django==4.0 在 Python 3.12 下失败而卡死。
- 只对真正需要验证的维度做矩阵:比如
python-version: [3.9, 3.11, 3.12]+test-env: [unit, integration],而不是叠加numpy-version和torch-version - 用
include显式定义合法组合,比用exclude屏蔽非法组合更可靠(github Actions 对exclude的匹配逻辑容易漏掉) - 矩阵 job 数量建议压到 6 个以内;超过 8 个大概率触发 GitHub 托管 runner 的并发限流(
Resource not accessible by integration错误)
Python 版本和依赖版本怎么配才不冲突
GitHub Actions 的 setup-python 动作本身不解决依赖兼容性,它只装 Python 解释器。真正的坑在 pip install 阶段——特别是当你用 requirements.txt 固定版本后,又试图在多个 Python 版本下复用同一份文件。
典型现象:pip install -r requirements.txt 在 Python 3.9 成功,3.12 报 ModuleNotFoundError: No module named 'distutils.util',因为 setuptools 某些旧版已移除 distutils 支持。
立即学习“Python免费学习笔记(深入)”;
- 按 Python 版本分组管理依赖:用
if: matrix.python-version == '3.12'切换不同的requirements-312.txt - 避免在矩阵中混用
pip install .和pip install -e .:前者可能跳过pyproject.toml中的构建后端检查,后者在某些矩阵 job 中因缓存污染导致ImportError - 如果项目用
poetry,别在每个 job 里都poetry install——改用poetry export -f requirements.txt --without-hashes提前生成适配各版本的 requirements 文件
怎么让矩阵测试快起来,又不漏关键路径
矩阵不是越多越好,而是要覆盖「执行路径差异最大」的组合。比如异步代码在 Python 3.11+ 有 asyncio.TaskGroup,但 3.9 只能用 asyncio.gather;这种逻辑分支必须测,但 black==23.1 和 black==24.2 在同一 Python 版本下通常没必要双测。
- 用
strategy.fail-fast: false确保一个 job 失败不影响其他 job 运行(默认是 true,容易误判整体失败) - 把耗时操作(如构建 wheel、下载大模型)提到矩阵外的单独 job,用
needs+outputs传 artifact,避免每个矩阵 job 重复执行 - 对非核心环境(如仅文档构建、仅 lint)不用矩阵,单独写成普通 job,用
if: github.event_name == 'push' && github.head_ref == 'main'控制触发条件
本地调试矩阵 job 为什么总和 CI 行为不一致
根本原因是 GitHub Actions 的 matrix 是运行时展开的,而本地用 act 或直接跑脚本时,环境变量、路径、甚至 shell 类型(linux runner 默认 bash,macos 是 zsh)都不同。最常踩的坑是 PATH 里没包含 ~/.local/bin,导致 pipx install black 装的命令在后续 step 找不到。
- 在每个 job 开头加
echo "PATH: $PATH"和which python,对比本地和 CI 输出 - 别依赖
source ~/.bashrc加载环境——runner 启动的是 non-interactive shell,不会自动读取 rc 文件 - 用
run: python -c "import sys; print(sys.version)"替代python --version,避免被 alias 或 wrapper 干扰
矩阵配置里最易被忽略的是 job 名称的可读性:name: Python ${{ matrix.python-version }} / ${{ matrix.test-env }} 比默认的 python-3.12 更容易定位失败点。还有就是 timeout-minutes 必须设,否则默认 6 小时超时,但很多矩阵 job 其实 10 分钟就该出结果了。