(译)改进 Android Studio 中的构建速度

翻译自 Improving build speed in Android Studio - Android Developers - Medium

改进构建速度

我们想让你在 Android Studio 中的生产力尽可能高。从之前跟开发者的讨论和调查中我们得知等待构建会降低生产力。

本文将分享一些用于准确定位影响构建速度的新的分析,以及我们目前在做的工作和你可以怎样防止构建速度变慢。

可能要感谢那些在设置中打开 “data sharing” 以分享其使用过程中的统计数据的那些开发者

度量构建速度的不同方式

The first thing we did was to create internal benchmarks* using open source projects (SignalAndroid, Tachiyomi, SantaTracker & skeleton of Uber) to measure the build speed impact of various changes to the project (code, resources, manifest etc).

我们工作的第一步是使用开源项目(SignalAndroid, Tachiyomi, SantaTracker, Uber) 建立内部指标来度量对项目的不同修改对构建速度的影响 (比如修改代码,资源以及 manifest)

例如,这是修改代码对构建速度的影响指标,它表明过去一段时间构建速度有非常大的提高。

我们也观察了真实世界中的数据,关注升级 Android Gradle 插件前后 debug 构建的速度变化。我们将这个数据作为新版本的实际改进。

下图显示新版本带来了极大提升,对比 2.3 版本构建时间下降了 50%。

最后看看构建时间随着时间的推移,而不关心 Android Gradle 插件的版本。我们将这个数据作为实际的构建速度。

If builds are indeed getting faster with each release, and we can see it in our data, why are they still getting slower over time?
We dug a little deeper and realized that things happening in our ecosystem are causing build to slow down faster than we can improve.
While we knew that project growth — with more code, more resource usage, more language features — was making build slower over time, we also discovered that there are many additional factors beyond our immediate control:

(那么问题来了,)随着每次新版本发布,如果构建速度真的变快了的话,为什么看到的实际构建速度却逐渐变慢?

我们深挖了一下,认识到实际的问题在于整个生态中正在发生的情况导致构建速度变慢,这个过程超过了我们的改进速度。

我们知道随着项目增长,更多的代码、更多的资源以及更多的语言特性,让项目构建速度逐渐变慢。我们还发现有许多额外因素超出我们的直接控制。

  • 2017 年底 Spectre and Meltdown 补丁对新的进程和 I/O 性能有影响,导致 clean builds 变慢 50% 到 140%
  • 第三方以及自定义 Gradle 插件:96% 的 Android Studio 开发者使用其他的 Gradle 插件 (一些开发者并没有遵守 新的最佳实践)
  • 大部分 注解处理器不是增量式的,每次修改代码都会全量编译。
  • Java 8 的使用。Java 8 的语言特性会引起 desugaring 过程。我们使用 D8 编译器减少了 desugaring 的影响
  • Kotlin 的使用。Kotlin 的注解处理器(KAPT)也会影响构建性能。我们正在跟 JetBrains 合作来最小化性能影响
  • 之前列出的那些荐跟真实项目不同,它们不会随着时间增长。测试指标只是模拟变化并且事后撤销,仅仅度量我们插件随时间的变化
    ** 3.3 关注基础工作以便未来的改进 (例如, 命名资源、增量注解器元素、Gradle workers 等等),所以几乎没有什么性能改进

我们能做什么

修复内部流程 & 持续性能提升

我们也承认许多内部来自 Google 提供的功能特性,所以我们改变内部流程以更好及时发现构建性能降低。

我们让 annotation processors 支持增量构建。写这篇文章时,Glide、Dagger 以及 Auto Service 都是增量式的,我们正在让其他库也支持增量构建。

我们在新发布的版本中还引入了更轻量级的 R 类生成方案,以及 lazy task 和 worker API,并继续跟 Gradle inc. 以及 JetBrains 合作来继续从整体上改进构建性能。

Attribution tools

最近一个调查表明大约 60% 的开发者不会分析构建性能,也不知道如何分析构建性能。因此我们计划改进 Android Studio 中的工具来提升社区中关于项目构建时间的认识和透明度。

我们正在探索如何直接在 Android Studio 中更好地提供插件和 task 如何影响构建性能的相关信息。

你能做什么

configuration 时间因 variant、模块以及其他因素变化,这里分享真实项目中的数据作为参考点。

如果你发现你的项目中 configuration 时间比上图中要慢很多,很可能是某些自定义构建逻辑(或第三方 Gradle 插件)影响了 configuration 时间。

使用工具

Gradle 提供免费的工具集用于分析构建。建议你使用 Gradle scan,它能提供关于构建的许多信息。如果你不能将自己的构建信息上传到 Gradle 服务器,则建议使用 Gradle profiler。Gradle profiler 能提供的信息要少一些,但不用担心它向服务器上传数据。

注意:构建扫描并不能用来有效分析 configuration 耗时,建议使用 JVM profiler 来分析 configuration 耗时。

优化构建配置和任务

这里有些优化构建速度的最佳实践可供参考。也可以参考 latest best practices

配置

  • 在 configuration 中只建立 task (通过 lazy API),避免任何 I/O 或其他操作 ( Configuration 不是用于执行 git 操作、读取文件、查询连接设备以其其他计算的)
  • 在 configuration 中建议所有 task。Configuration 并不知道实际会构建什么

优化任务

  • 为每个 task 都声明 inputs/outputs (即使没有任何文件),以保证任务可增量编译以及可缓存
  • 将复杂步骤分解成多个任务,以便增量编译和可缓存 (这样可以让某些 task 保持 up-to-date 状态或者并行)
  • 确保 task 不会写入或删除其他 task 的输出目录
  • 在 plugin/buildSrc 中添加自己的 task,而不是在 build.gradle 中添加

我们关心你作为开发者的生产力。我们将继续努力让构建更快速,也希望这些 tips 和 guidelines 能帮你减少构建时间,而你更加专注开发优秀的应用。