这是关于增量开发的系列博文的第二篇,增量开发是软件开发过程中经常做小改动的部分。我们将讨论即将推出的Gradle构建工具的功能,这些功能大大改善了围绕这一用例的反馈时间。在上一篇文章中,我们介绍了Gradle 6.5的文件系统观察。
在Gradle 6.6中,我们引入了一个名为配置缓存的实验性功能,通过缓存配置阶段的结果并在后续的构建中重复使用,显著提高了构建性能。使用配置缓存,Gradle可以在没有影响到构建配置的情况下完全跳过配置阶段,比如构建脚本的变化。

在此基础上,当重复使用配置缓存时,更多的工作在默认情况下是并行运行的,并且依赖性解析被缓存起来。配置和执行阶段的隔离,以及任务的隔离,使得这些优化成为可能。
请注意,配置缓存与构建缓存不同,构建缓存是对构建产生的输出进行缓存。配置缓存只抓取配置阶段的状态。它也与IDE的同步和导入过程分开,后者目前没有从配置缓存中受益。
为了缓存配置结果,Gradle应用了一些强有力的要求,插件和构建脚本都需要遵循。许多插件,包括一些核心的Gradle插件,都还没有满足这些要求。此外,一些Gradle功能中对配置缓存的支持也还没有实现。因此,你的构建和你所依赖的插件很可能需要修改以满足要求。Gradle会报告在你的构建逻辑中发现的问题,以协助你使你的构建与配置缓存一起工作。
配置缓存目前是 高度实验性而不是默认启用的。我们提前发布它,是为了收集社区的反馈,同时我们也在努力稳定这个新功能。
也就是说,我们致力于使配置缓存为生产做好准备,最终目标是默认启用它。你可以期待它在接下来的Gradle版本中会有明显的改善。
配置缓存的操作
建议从最简单的任务调用开始。在启用配置缓存的情况下运行help ,是一个很好的第一步。
构建时间的改进
该功能的实际影响取决于许多因素,但总的来说,它应该会导致构建时间的大幅减少。我们已经在大型的实际构建中看到了大幅度的改进,让我们来看看其中的一些。
Java 构建
在一个有大约500个子项目和复杂构建逻辑的大型Java企业构建中,运行:help ,从8秒下降到0.5秒。那是16倍的速度。当然,运行:help 并不那么有用,但它可以让我们了解到配置阶段所节省的时间。在相同的构建中,在改变了一些执行代码后,运行assemble ,从40秒下降到13秒.
现在我们来看看gradle/gradle的构建。它有一百个子项目和一个相当复杂的构建逻辑。你可以用它来重现这些结果。在对实现进行修改后,运行一个测试从16.4秒降到13.8秒,跳过了~2秒的配置阶段。
你也可以看到,执行阶段受益于配置缓存,但在这种情况下被编译和运行测试所支配。
安卓系统的构建
另一个值得注意的例子是一个非常大的现实世界的Android构建,其中有大约2500个子项目。在该构建中,运行:help ,从25秒下降到0.5秒,这是50倍的速度!运行一个更有用的构建,比如在改变了一些实现后组装APK,从50秒下降到20秒,几乎快了3倍。
在Santa Tracker Android项目中,我们看到一个小的实现变化在构建时间上有如下改进。
配置阶段被削减了一半,从129毫秒减少到63.5毫秒。你还可以看到,由于更多的任务并行化和依赖解决的缓存,执行阶段被配置缓存加速了。
如果你想用上述构建进行重现,或者测量你自己的构建,你可以按照这个资源库的说明使用Gradle Profiler。请注意,Gradle Profiler将显示一个稍微不同的画面,更接近于来自IDE的经验,因为两者都使用Gradle Tooling API。这就跳过了你使用命令行时发生的启动Gradle客户端JVM的固定成本。
它是如何工作的?
当配置缓存被启用后,你为一组特定的任务运行Gradle,例如通过运行./gradlew check ,Gradle会检查配置缓存条目对所请求的任务集是否可用。如果可用,Gradle会使用这个条目,而不是运行配置阶段。缓存条目包含要运行的任务集的信息,以及它们的配置和依赖信息。
当你第一次运行一个特定的任务集时,配置缓存中不会有这些任务的条目,因此Gradle会正常运行配置阶段。
- 运行init脚本。
- 运行构建的设置脚本,应用任何要求的设置插件。
- 配置并构建 buildSrc 项目(如果存在的话)。
- 运行构建脚本,应用任何要求的项目插件。
- 计算所需任务的任务图,运行任何延迟的配置动作。
在配置阶段之后,Gradle会将任务图的状态写入配置缓存,为以后的Gradle调用做一个快照。然后执行阶段照常运行。这意味着在你第一次运行一组特定的任务时,你不会看到任何构建性能的提高。
当你随后用这组任务运行Gradle时,例如再次运行./gradlew check ,Gradle将直接从配置缓存中加载任务和它们的配置,完全跳过配置阶段,并行运行所有任务。在使用一个配置缓存条目之前,Gradle会检查该条目的 "构建配置输入",如构建脚本,是否有变化。如果一个构建配置输入发生了变化,Gradle将不使用该条目,而是像上面那样再次运行配置阶段,并保存结果以便以后重复使用。
要求和限制
为了将任务图的状态捕捉到配置缓存中,并在以后的构建中再次重新加载,Gradle对任务和其他构建逻辑应用了某些要求。这些要求中的每一项都被视为配置缓存的 "问题",默认情况下,如果存在违规行为,则会导致构建失败。
如果发现任何缓存或重复使用配置的问题,会生成一份HTML报告,以帮助你诊断和解决这些问题。
如果你遇到这种问题,你的构建或使用的Gradle插件可能需要调整。关于如何使用该报告的更多信息,请参见文档中的Troubleshooting部分。
你可以在配置缓存文档中找到支持的核心插件集和尚未实现的Gradle功能集。
最新的Android Gradle插件预览版,4.2.0-alpha07 ,在写这篇文章时,可以使用配置缓存。最新的Kotlin Gradle插件,1.4.0-RC ,在写这篇文章时,可以在简单的JVM项目上工作,发出一些问题。Kotlin1.4.20 是目前完全兼容的插件的目标。这个信息可以在gradle/gradle#13490和最常用的社区插件的状态一起找到。
尝试配置缓存
如果你想看看你的项目是如何从配置缓存中受益的,下面是你可以尝试的方法。
首先,确保你运行Gradle 6.6或更高版本。为了启用配置缓存,你需要在命令行中传递--configuration-cache 。或者将以下内容加入到项目目录下或Gradle用户主页上的gradle.properties 文件,这样你就不需要在每次构建时传递命令行选项。
org.gradle.unsafe.configuration-cache=true
请记住,只有在随后的构建中使用相同的请求任务时,你才会看到性能的改善,启用该功能。如果你想对你的构建进行基准测试,你可以通过Gradle Profiler按照这个软件库中的说明来轻松完成。
如果你遇到任何问题,请查看支持的核心插件或社区插件,在用户手册中学习如何排除故障。你也可以阅读我们推荐的采用步骤。
如果你仍然有问题,如果你认为是Gradle的问题,请打开一个Gradle问题,或者查看gradle/gradle#13490的支持的社区插件问题。你也可以在Gradle社区Slack的#configuration-cache 频道中获得帮助。