Gradle 构建缓存 Beta 版介绍
介绍
在 Gradle 3.5 中引入,以减少构建时间。
它有什么作用? #
构建缓存重用本地 Gradle 任务的输出,并在机器之间共享任务输出。在许多情况下,这将加速平均构建时间。
构建缓存是 Gradle 增量构建特性的补充,后者优化了尚未构建的本地更改的构建性能。许多 Gradle 任务被设计为增量的,这样如果任务的输入和输出没有改变,Gradle 就可以跳过该任务。即使任务的输入发生了变化,一些任务也只能重建已更改的部分。当然,这些技术只有在之前本地构建已经存在输出时才有效。过去,在全新的检出上构建或执行“clean”构建需要从头开始构建所有内容,即使这些构建的结果已经在本地或另一台机器(例如持续集成服务器)上创建。
现在,Gradle 使用任务的输入作为键来唯一标识任务的输出。启用构建缓存功能后,如果 Gradle 可以在构建缓存中找到该键,Gradle 将跳过任务执行,并直接将输出从缓存复制到构建目录中。这可能比再次执行任务快得多。
特别是,如果您正在使用持续集成服务器,您可以配置 Gradle 将任务输出推送到共享构建缓存。当开发人员构建时,CI 上已构建的任务输出将被复制到开发人员的机器上。这可以极大地改善开发人员的本地构建体验。
当使用本地构建缓存时,每当您切换分支时,Gradle 可以跳过任务执行并从本地缓存中拉取以前的输出,而不是重建项目的大部分。
它是如何工作的? #
可缓存的 Gradle 任务旨在声明所有可能影响任务输出的内容作为输入。Gradle 通过哈希处理任务的所有输入来计算构建缓存键。该构建缓存键唯一标识任务的输出。这是每个任务实现的可选功能,因此并非每个任务都是可缓存的或需要缓存的。几个内置的 Gradle 任务(JavaCompile
, Test
, Checkstyle
)已启用缓存,以加速典型的 Java 项目。
任务的构建缓存键考虑了
- 任务通过注解(例如
@InputFiles
)或运行时 TaskInputs API 定义的所有输入的值。 - 任何文件输入的内容(和相对路径)。
- 任务的类路径,包括使用的任何插件和 Gradle 版本。
- 任何任务操作的类路径,其中可以包括构建脚本。
当启用构建缓存功能时,如果任务不是最新的,Gradle 将检查任何配置的构建缓存是否包含与任务的构建缓存键匹配的项。如果 Gradle 没有找到匹配项,任务将照常执行。执行后,如果配置为这样做,Gradle 将收集任务的所有输出并将它们推送到构建缓存。如果 Gradle 找到匹配项,任务的输出将被删除,并且以前的输出将被复制到输出目录中。
它有帮助吗? #
自 2016 年 11 月以来,我们一直在 Gradle CI 构建中使用构建缓存。我们还有一些合作伙伴在他们的构建中尝试了构建缓存。我们无法直接分享他们的数据,但他们看到了与我们类似的 CI 和开发人员构建方面的改进。平均而言,我们看到每次提交的总构建时间减少了 25%,但某些提交甚至更好(减少了 80%),而中位数构建减少了 15%。
这是另一个关于 Gradle 缓存和非缓存构建之间所花费分钟数的视图。您可以看到,对于我们来说,这些减少转化为大约在 360 分钟的构建中节省了 90 分钟。
构建缓存是一个通用功能,它可以在可能的情况下避免重新执行任务,因此无论构建大小都可以在某种程度上受益。您的项目结构将影响您总体可以获得多少收益。如果您的项目由单个单体模块组成,Gradle 还有其他可能有所帮助的功能,例如增量编译或复合构建。我们将在未来的博客文章和Gradle Summit 上提供更多关于如何充分利用构建缓存的信息。
今天就让你的构建更快 #
Gradle 3.5 版本是第一个包含构建缓存功能的版本。
我们预计构建缓存功能将在下一个版本中全面可用,但我们希望每个项目都尝试一下构建缓存 Beta 版。为此,我们希望您为我们尝试 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 指南,以便您更容易缓存更多任务并开发缓存友好的任务。
感谢您的持续帮助和支持。请考虑使用我们上面概述的三个步骤,通过构建缓存使您的构建更快。