Gradle 构建缓存 Beta 版简介

Gradle 3.5 中引入,以减少构建时间。

它有什么作用?

构建缓存在本地重用 Gradle 任务的输出,并在机器之间共享任务输出。在许多情况下,这将加速平均构建时间。

构建缓存是对 Gradle 增量构建功能的补充,增量构建功能可以优化对尚未构建的本地更改的构建性能。许多 Gradle 任务被设计为 增量 的,因此如果任务的输入和输出没有改变,Gradle 可以跳过该任务。即使任务的输入发生了改变,一些任务 也可以只重建发生改变的部分。当然,这些技术只有在之前本地构建已经存在输出的情况下才能起作用。过去,在全新检出或执行“clean”构建时,需要从头开始构建所有内容,即使这些构建的结果已经存在于本地或其他机器(例如持续集成服务器)上。

现在,Gradle 使用任务的输入作为键来唯一标识任务的输出。如果启用构建缓存功能,Gradle 可以在构建缓存中找到该键,则会跳过任务执行,并将输出直接从缓存复制到构建目录。这比再次执行任务快得多。

特别是,如果您使用的是持续集成服务器,您可以配置 Gradle 将任务输出推送到共享构建缓存。当开发人员构建时,已经在 CI 上构建的任务输出会被复制到开发人员的机器上。这可以极大地改善开发人员的本地构建体验。

当使用本地构建缓存时,Gradle 可以跳过任务执行,并从本地缓存中提取之前的输出,而不是在您切换分支时重建项目的很大一部分。

它是如何工作的?

可缓存的 Gradle 任务被设计为将所有可能影响任务输出的内容声明为输入。Gradle 通过对任务的所有输入进行哈希运算来计算构建缓存键。该构建缓存键唯一标识任务的输出。这是一个针对每个任务实现的可选功能,因此并非每个任务都是可缓存的或需要缓存的。几个内置的 Gradle 任务(JavaCompileTestCheckstyle)启用了缓存功能,以加快典型 Java 项目的速度。

任务的构建缓存键考虑了

  • 任务通过注释(例如 @InputFiles)或运行时 TaskInputs API 定义的所有输入的值。
  • 任何文件输入的内容(以及相对路径)。
  • 任务的类路径,包括任何插件和使用的 Gradle 版本。
  • 任何任务操作的类路径,可能包括构建脚本。

当启用构建缓存功能时,Gradle 会在任务未更新时检查任何已配置的构建缓存中是否包含与任务的构建缓存键匹配的项。如果 Gradle 未找到匹配项,则任务将照常执行。执行后,Gradle 将收集所有任务的输出并将它们推送到构建缓存(如果已配置这样做)。如果 Gradle 找到匹配项,则会删除任务的输出,并将以前的输出复制到输出目录。

这有帮助吗?

自 2016 年 11 月起,我们一直在 Gradle CI 构建中使用构建缓存。我们还有一些合作伙伴一直在尝试在他们的构建中使用构建缓存。我们不能直接分享他们的数据,但他们也看到了与我们类似的 CI 和开发人员构建改进。平均而言,我们看到每个提交的构建总时间减少了 25%,但有些提交甚至更好(减少了 80%),而中位数构建减少了 15%。

Stage 3 %-Improved

以下是 Gradle 缓存构建和非缓存构建之间花费的分钟数的另一个视角。您可以看到,减少量转化为我们 360 分钟的构建中节省了大约 90 分钟。

Stage 3 comparison

构建缓存是一个通用功能,它可以避免在可以的情况下重新执行任务,因此大型和小型构建都可以从中受益。项目的结构将影响您总体上可以获得多少收益。如果您的项目包含单个单体模块,Gradle 还有其他功能可能也有所帮助,例如 增量编译复合构建。我们将在以后的博文中和 Gradle 峰会 上提供有关如何充分利用构建缓存的更多信息。

立即让您的构建更快

Gradle 3.5 版本 是第一个包含构建缓存功能的版本。

我们预计构建缓存功能将在下一个版本中普遍可用,但我们希望每个项目都尝试一下构建缓存测试版。为此,我们希望您尝试 3 件事。

1) 在一个简单的项目上尝试

升级到 3.5 后,选择一个简单的 Java 项目并运行

gradle --build-cache clean assemble
gradle --build-cache clean assemble

第二次构建应该更快,因为一些任务输出是从第一次构建中重用的。这些输出将从您的本地构建缓存中提取,该缓存位于您的 GRADLE_USER_HOME 中的目录中。

2) 尝试在机器之间共享输出

为了使用共享的远程缓存,我们提供了一个 推荐的配置,它使用您的持续集成构建来填充共享构建缓存,并允许所有开发人员从该构建缓存中提取。

您将需要一个远程构建缓存后端来在开发人员之间共享。我们提供了一个 构建缓存节点 docker 镜像,它充当远程 Gradle 构建缓存,并且可以与 Gradle Enterprise 连接以进行集中管理。缓存节点也可以在没有 Gradle Enterprise 安装的情况下使用,但功能有限。

3) 给我们反馈

如果您有任何反馈,我们很乐意听到。如果您有可以分享的 构建扫描,那就更好了。

我们很高兴在 Gradle 3.5 中发布 Gradle 构建缓存功能以供反馈,但我们知道我们还需要做更多工作才能使构建缓存稳定且高效。我们有一些 已知问题,您应该在 在 GitHub 上提出新问题 之前检查。

目前,我们不建议您在不了解风险的情况下将构建缓存启用用于生产构建。有一些 已知问题 可能会导致您的构建失败或产生错误的输出,但您对问题类型或成功的反馈对于构建缓存功能的成熟非常有价值。您可以在构建中配置构建缓存,并通过设置 org.gradle.caching=true 或使用 --build-cache 运行来试用它,而不会影响所有构建。

为了对 Gradle 的构建缓存进行试用,我们使用了单独的 CI 作业来运行启用构建缓存的构建。这使我们能够比较相同更改集在启用和禁用构建缓存的情况下构建时间。

感谢和路线图

尝试过构建缓存后,您可能对为什么构建的更多部分不可缓存有一些疑问。无论您使用哪种构建缓存后端,Gradle Enterprise 2017.2 都提供了一些功能来了解构建缓存的使用和行为,通过收集数据,无论构建缓存是否启用。构建扫描会跟踪任务未被缓存的原因。如果任务存在特定问题,例如没有输出或未为其启用可缓存性,则该任务可能不会被缓存。您可以在构建扫描时间轴中搜索这些原因的每一个。

在未来的 Gradle 和 Gradle Enterprise 版本中,我们将收集更多与构建缓存和任务可缓存性相关的信息,以便更轻松地诊断构建失败或构建缓存性能低下。

对于下一个版本 Gradle 4.0,我们打算专注于使构建缓存对所有行为良好的构建安全启用,并为 Gradle 无法安全缓存任务输出的情况提供反馈。这也意味着我们将提供一个行为良好的本地构建缓存和几个验证检查。

对于随后的版本,我们打算花时间扩展我们的文档和 Gradle 指南,让您更轻松地缓存更多任务并开发缓存友好的任务。

感谢您持续的帮助和支持。请考虑使用我们上面概述的三个步骤 使您的构建更快,使用构建缓存。

讨论