mcpField
B
build-parallelism

build-parallelism

github.com/dotnet开发5.8k3.6k 次安装1 天前更新
代码仓库

关于 build-parallelism

面向 .NET 开发者的 MSBuild 并行构建诊断技能,借助 binlog 定位关键路径和串行依赖,并提出针对性优化方向。

主要功能

  1. 01检查构建节点与项目耗时
  2. 02分析关键路径和依赖链
  3. 03定位不必要的项目引用
  4. 04借助 binlog MCP 分析构建耗时
  5. 05提供图构建与 CI 并行建议

适用场景

  1. 01排查多核环境下构建仍然缓慢
  2. 02识别导致构建串行化的依赖
  3. 03用 binlog 定位耗时项目和目标

MCP 相关

指导使用 Microsoft.AITools.BinlogMcp 的 binlog MCP 工具,分析项目、目标及并行构建耗时。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotnet/skills --skill build-parallelism

安装后在 Claude Code 中输入/build-parallelism确认已加载。

详细介绍

诊断并行构建缓慢的问题(从这里开始)

请按顺序完成此检查清单——它针对的是常见的根本原因(串行依赖链,无论有多少核心都无法并行化):

  1. 检查实际有多少个工作节点参与了构建。 使用 dotnet build /bl:{}(PowerShell:dotnet build '-bl:{}')捕获 binlog,并检查节点时间线,确认运行的节点是否多于一个。通过 SDK 的 MSBuild 转发路径运行的每个 dotnet CLI 命令(build、msbuild、test、pack、publish 等)默认都会启用 /maxcpucount(多个节点);-m:1 会强制使用单个节点。直接调用 MSBuild.exe 默认按顺序执行,因此需要显式传入 -m,才能启用并行工作节点。
  2. 找出关键路径。 根据 binlog 查看各项目的耗时和节点时间线。如果总构建时间 ≈ 某条依赖链上各项目耗时之和,那么瓶颈就是这条链,而非 CPU 数量。
  3. 明确指出依赖链,例如 Core → Api → Web → Tests。无论 -m 的值有多大,长串行链依然会串行执行,因为每个项目都要等待其前置项目完成。
  4. 查找会拉长依赖链的不必要 ProjectReference 边——只需要确保构建顺序(而不需要输出程序集)的引用,或可以改为 PackageReference 的引用,都会造成不必要的串行执行。
  5. 建议扁平化依赖结构:打破虚假的依赖关系,让互不依赖的项目可以并行构建,并考虑使用 /graph 改善调度。

MSBuild 并行模型

  • /maxcpucount(或 -m):工作节点(进程)数量
  • 每个 dotnet CLI 命令(build、msbuild、test、pack、publish 等)默认都会通过 SDK 的共享 MSBuild 转发路径传入 /maxcpucount;-m:1 会覆盖此设置,改为使用单个节点
  • 直接调用 MSBuild.exe 默认按顺序执行,需要显式传入 -m
  • 建议:不指定数字的 -m 表示使用所有逻辑处理器
  • 每个节点一次构建一个项目
  • 项目根据依赖关系图进行调度

项目依赖关系图

  • MSBuild 按依赖顺序(拓扑排序)构建项目
  • 关键路径:最长的项目依赖链决定了最短构建时间
  • 瓶颈:如果项目 A 依赖于 B、C、D,且 B 耗时 60s,而 C 和 D 耗时 5s,那么 B 就是瓶颈
  • 诊断:将 binlog 重放为诊断日志,并使用 performancesummary 检查 Project Performance Summary——其中会显示各项目的耗时;搜索 node.*assigned 检查调度情况
  • 宽图(包含许多互不依赖的项目)有利于并行化;深图(包含很长的依赖链)则不利于并行化

图构建模式(/graph)

  • dotnet build /graph 或 msbuild /graph
  • 作用:MSBuild 会在构建前构建完整的项目依赖关系图
  • 优点:改善调度、避免重复评估,并支持隔离构建
  • 限制:所有项目都必须使用 <ProjectReference>(不能使用以编程方式创建的 MSBuild 任务引用)
  • 适用场景:包含许多项目的大型解决方案、CI 构建
  • 不适用场景:在构建时动态发现引用的项目

优化项目引用

  • 只有在确认 <ProjectReference> 不必要后,才将其移除;缓慢但有效的依赖必须保留在依赖关系图中
  • 使用 <ProjectReference ... SkipGetTargetFrameworkProperties="true"> 避免额外的评估
  • 对于只为确保构建顺序的依赖,使用 <ProjectReference ... ReferenceOutputAssembly="false">
  • 考虑是否应将 ProjectReference 改为 PackageReference(预构建 NuGet 包)
  • 使用 solution filters(.slnf)构建解决方案的子集

BuildInParallel

  • 在自定义目标中使用 <MSBuild Projects="@(ProjectsToBuild)" BuildInParallel="true" />
  • 如果没有设置 BuildInParallel="true",MSBuild 任务会按顺序批处理项目
  • 确保 /maxcpucount 大于 1,才能生效

多线程 MSBuild 任务

  • 单个项目构建中的各个任务可以多线程运行
  • 实现 IMultiThreadableTask 的任务可以在多个线程上运行
  • 任务必须通过 [MSBuildMultiThreadableTask] 声明线程安全性

使用 Binlog 分析并行性

主要方法:binlog MCP(首选)

使用 binlog MCP 服务(Microsoft.AITools.BinlogMcp,在 binlog MCP 命名空间下公开):

  1. 使用 expensive_projects 工具 → 找出最慢的项目,并比较单个项目与整体构建时间
  2. 使用 expensive_targets 工具 → 找出瓶颈目标
  3. 使用 project_target_times 工具 → 深入查看特定项目的目标级耗时
  4. 理想情况下:构建时间应远短于各项目耗时之和(并行性)
  5. 如果构建时间 ≈ 各项目耗时之和:串行依赖过多,或某个慢项目阻塞了其他项目
备用方法:重放文本日志(MCP 不可用时)

分步操作:

  1. 重放 binlog:dotnet msbuild build.binlog -noconlog -fl "-flp:v=diag;logfile=full.log;performancesummary"
  2. 查看 full.log 末尾的 Project Performance Summary
  3. 理想情况下:构建时间应远短于各项目耗时之和(并行性)
  4. 如果构建时间 ≈ 各项目耗时之和:串行依赖过多,或某个慢项目阻塞了其他项目
  5. grep 'Target Performance Summary' -A 30 full.log → 找出瓶颈目标
  6. 考虑拆分大型项目或优化关键路径

CI/CD 并行性提示

  • 在 CI 中使用 -m(许多 CI 运行器有多个核心)
  • 如果需要极高的并行性,可考虑将解决方案拆分为多个构建阶段
  • 使用构建缓存(NuGet 锁定文件、确定性构建),避免重新构建未更改的项目
  • dotnet build /graph 适用于结构化 CI 管道

评论

支持 Markdown