建造,为什么你走得慢?

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

当构建花费的时间太长时,了解它在做什么会非常有帮助。 Bazel 具有内置工具,可让您可视化每个线程在构建的任何给定时刻正在做什么,以及哪些构建步骤正在减慢您的整体构建速度。

要试用 Bazel 的分析工具,请使用 --profile 选项构建您最喜欢的(或者更确切地说,最不喜欢的)目标:


 $ bazel build --profile=myprofile.out //snail:slow-lib

这会将配置文件写入当前目录中名为 myprofile.out 的文件。构建完成后,您可以查看此文件,但它并不是真正为人类阅读而设计的。相反,将其插入 Bazel 的 analyze-profile 命令:


 $ bazel build --profile=myprofile.out //snail:slow-lib

现在你等待 Bazel 分析个人资料信息并欣赏这张我前几天看到的蜗牛在多米诺骨牌上行走的照片(比例包括一分钱):

使您的项目构建速度比这更快。

(拍完这张照片后,我把蜗牛移到草地上,因为我很确定它在纽约市人行道中间并不高兴。)

叮,分析大概完成了。现在您可以打开 myprofile.out.html 并查看您的构建,分解为数百或数千个单独的步骤。输出的屏幕截图:

我上传了 HTML 页面,这样您就可以 在此处查看全部内容 并使用它(它将在新选项卡中打开)。

我在上面的配置文件中使用了 示例应用程序 中的 //android 目标,因为它比玩具示例更丰富。

该图表显示了在任何给定时间(每行一个线程)在构建期间所有 200 个构建线程正在做什么。构建分为几个“阶段”,在图表上显示为不同颜色的列:

  1. 前 1.5 秒(深灰色)用于初始化构建命令,这意味着它只是解析选项和设置缓存。
  2. 接下来的约 1 秒(绿色)是加载阶段,Bazel 确定它需要哪些包,下载外部依赖项,并查找和解析 BUILD 文件。
  3. 接下来的 ~100 毫秒(浅灰色条)是分析依赖项阶段,Bazel 在此阶段找出哪些依赖项已缓存且干净,因此不需要重建。
  4. 最后,Bazel 进入构建阶段(粉红色背景),实际构建所有需要构建的东西。

您可以在图例上看到其他几个阶段,但在大多数情况下,它们太短,甚至无法在图表上看到。

在图表下方,有一个“执行阶段”部分。 “执行”在这种情况下可能有点混乱:它指的是执行构建,而不是运行您的程序。执行阶段映射到上图中的粉红色阶段。在本节中有一个名为“关键路径”的子节,它分解了您的构建正在等待的内容:


 $ bazel build --profile=myprofile.out //snail:slow-lib

如您所见,在构建 libandroid_builder_lib.jar 及其参数文件时,构建被“阻塞”了超过 8 秒。幸运的是,这些文件不应该在构建之间改变(除非你更新你的 Android SDK,这不应该在每个构建之间发生)。如果我更改 libactivities.jar(程序的实际内容)并重建,我会得到:


 $ bazel build --profile=myprofile.out //snail:slow-lib

是此增量构建的新配置文件页面。

请注意,关键路径现在只有 2.718 秒,而不是 13.339!如果我们查看配置文件,我们可以看到新的关键路径更加简洁:


 $ bazel build --profile=myprofile.out //snail:slow-lib

现在构建 libactivities.jar 是关键路径上最重量级的操作,因此我们可以通过将其分解成单独的库来解决这个问题,这些库不必在每次发生变化时都重新编译。

Bazel 生成的配置文件可能……很密集……所以如果您需要任何解释它们的帮助,请随时在 邮件列表 中询问。此外,如果您对这个主题的更多信息感兴趣,请查看 有关分析的文档