Gradle 和 Maven:性能比较
加快构建速度的商业案例
Gradle 旨在帮助组织更快地交付更好的软件。更快的构建是实现这一目标最直接的方式之一;工程师在不等待软件构建时有更多机会交付软件。CI 实例花费更少的时间进行不必要的重建,需要更少的 CPU 资源,并更早地提醒工程师。
案例研究
2017 年,我们与一个 600 名工程师的团队合作。平均而言,每位工程师每周运行约 42 个构建。该团队估计每位工程师每分钟的成本为 1.42 美元,他们每年至少工作 44 周。
这意味着他们每分钟都能让开发者构建速度更快,他们就可以为工程师节省 1,600,000 美元的等待时间。
600 名工程师 * 1.42 美元/分钟 * 42 次构建/周 * 44 个工作周/年 = 1,600,000 美元/年
如果构建速度快 90% 会怎样?
性能改进具有额外的强大经济影响。例如,CI 实例花费更少的时间进行不必要的重建,也需要更少的 CPU 资源,更早地提醒工程师,并构建更小的变更集,这使得调试 CI 故障更容易。
你呢?
我们一次又一次地发现,投资于构建性能的组织通常会迅速收回投资,更快地交付产品,并拥有更快乐、更高效的团队。
在一篇关于速度、性能和人类感知的入门文章中,Ilya Grigorik 认为,心智上下文切换可能在几秒钟后就会发生——使用极快构建工具的工程师更有可能保持“心流”状态,从而更有效率。
Gradle 比 Maven 快 100 倍
我们已经在各种常见场景的项目上进行了性能测量,以估算从 Maven 迁移到 Gradle 的成本摊销。
以下结果是在 MacBook Pro 2018、2.9 GHz Intel Core i9、32 GB RAM、SSD、OSX Mojave (10.14.2) 上生成的,使用 10 次运行的平均值。
了解测试项目以及如何使用以下说明重现性能结果。
场景:Java 库
为了衡量对典型库项目的影响,我们将 Apache Commons Lang 3 项目从 Maven 转换为 Gradle(使用 Java Library 插件)。
Gradle 运行测试速度快 1.7 倍,使用构建缓存时构建速度快 30 倍!
场景:小型多项目构建
以下是 10 模块多项目构建的常见任务的结果,最类似于微服务集合。每个子项目有 50 个源文件和 50 个测试源文件。
Gradle 在干净构建方面快 2-3 倍,增量更改方面快约 7 倍,当 Gradle 任务输出被缓存时快 14 倍。
此 GIF 并排显示了 clean build
场景,以便您可以感受差异(不使用构建缓存)。
场景:中型多项目构建
以下是 100 模块多项目构建的常见任务的结果,这些模块位于单个存储库中。每个子项目有 100 个源文件和 100 个测试文件。
Gradle 在干净构建方面快 4-5 倍,增量更改方面快约 40 倍,当 Gradle 任务输出被缓存时快 13 倍。
场景:大型多项目构建
以下是 500 模块多项目构建的常见任务的结果,这些模块位于单个存储库中。每个子项目有 100 个源文件和 100 个测试文件。
Gradle 在干净构建方面快 3-10 倍,增量更改方面快约 85 倍,当 Gradle 任务输出被缓存时快 13 倍。
场景:大型单体应用程序
虽然在一个项目中拥有所有代码的情况很少见,但拥有多模块构建非常常见,其中大部分代码位于一个或几个模块中,这些模块比其余模块大得多。此场景是对此类项目的近似——一个包含 50000 个源文件和 50000 个测试文件的单个项目。
Gradle 在干净构建方面快 2-3 倍,增量更改方面快约 7 倍,当 Gradle 任务输出被缓存时快 3 倍。
性能结果摘要
- 在所有结果中,Gradle 在每种场景中至少快 2 倍。
- 在构建增量更改时,Gradle 比 Maven 快 7 到 85 倍; 收益随着子项目数量的增加而增加。
- 当任务输出可以通过 Gradle 的构建缓存解析时,Gradle 构建比 Maven 构建快 3 到 30 倍。
优于 Maven 的性能优势,使其成为可能
通过选择 Gradle,您将从与 Apache Maven 相比巨大的性能改进中获益:Gradle 实施了广泛的策略来加快您的构建速度
- Gradle 守护程序是一个长期存在的进程,它将构建信息“热”保存在内存中
- 各种类型任务的增量任务输入和输出使得无需再次运行
clean
- 增量编译分析您的源和类之间的依赖关系,并仅重新编译受更改影响的那些
- 构建缓存在切换分支或运行干净构建时从缓存中获取结果,并且相同的输出已经在组织中的其他地方生成。
- Gradle 的 智能类路径分析器在库的二进制接口未更改时避免不必要的编译
- 使用 Java Library 插件更好地建模依赖关系,减少了编译类路径的大小,这对性能有很大的积极影响
上述性能结果表明,所有这些功能结合在一起会产生很大的不同。
进一步提升性能
您可能已经注意到,从上述测量中获得的最极端的性能提升是那些利用 Gradle 构建缓存的性能提升。
Develocity 配备了一个远程构建缓存,具有开箱即用的便捷管理工具,更不用说可以精美地可视化和比较构建并查看整个组织的构建的工具。获得更快、更顺畅的迁移,以便您可以专注于交付软件。借助 Develocity Build Cache,Gradle 构建工具用户通常可以额外减少 50% 的平均构建时间。
注意: Gradle 和 Maven 用户都可以利用 Develocity 中提供的构建缓存技术。Gradle 用户通常可以额外减少约 50% 的构建时间,而 Maven 用户通常可以减少约 90%。观看此视频以了解有关 Develocity Maven 构建缓存技术和商业案例的更多信息。
轮到你了
重现结果和方法
对于我们的测量,我们使用了以下测试项目,对应于真实开发者常遇到的四种场景。
- 10 模块项目,每个模块有 50 个源文件和 50 个测试文件
- 100 模块项目,每个模块有 100 个源文件和 100 个测试文件
- 500 模块项目,每个模块有 100 个源文件和 100 个测试文件
- 大型单体应用程序,在一个项目中包含 50000 个源文件和 50000 个测试文件。
您可以通过按照 GitHub 上发布的说明自行生成这些项目。
为什么干净构建的时间如此重要?
与 Maven 相比,Gradle 可以执行快速、可靠的增量构建。尽管如此,执行干净构建所需的时间仍然是一个相关的指标。它反映了重要的真实世界场景
- 始终使用没有本地状态保留的新 slave 的 CI 构建。
- CI 构建始终作为干净构建完成的文化。
- 开发人员从新的 checkout 构建
- 开发人员构建在代码更改很多的地方。这不完全是干净构建。但由于几乎所有内容都需要重建,因此干净构建时间最能反映这种情况。
对于 Gradle,我们测量 clean assemble
,它清除所有输出,然后编译类、处理资源并构建 jar。它不执行测试。对于 Maven,我们测量 clean package
,它执行相同的操作,但我们需要使用 -Dmaven.skip.test=true
显式排除测试执行。
关于增量构建
典型的开发人员工作流程是编辑一个或几个源文件并重新构建。Maven 的增量编译已损坏(请参阅 此错误,另一个错误 或 此错误),您被迫始终执行干净构建。相反,当只有少数源文件发生更改时,Gradle 构建可靠且更快(与干净构建相比)。
在 ABI 兼容更改场景中,我们对方法的实现应用更改,这种更改不会更改组件的应用程序二进制接口 (ABI)。
在 ABI 不兼容更改场景中,我们对公共方法的公共签名应用更改。您可以在我们的关于避免编译和增量编译的博客文章中了解更多信息。
关于 Gradle 的构建缓存
Gradle 构建缓存重用本地 Gradle 任务的输出,并在机器之间共享任务输出。在许多情况下,这将加快平均构建时间。在Gradle 构建缓存简介博客文章中了解更多信息。
当在分支之间切换时,构建缓存也非常有帮助,因为来自先前构建的构建输出被保留,并且不必重新创建。性能节省与上面的缓存构建相当,其中 Gradle 比 Maven 快 17 到 100 倍。
后续步骤
现在使用 Gradle 构建工具可以实现极端的性能提升。
为了让您能够高效地实现和保持这些数字,我们创建了Develocity 平台,该平台附带
- 具有便捷管理工具的高度可扩展的远程构建缓存
- Build Scan™,允许您的组织收集对开发人员在本地或 CI 服务器上运行的构建的深入见解。利用这些数据来减少中断并持续提高构建的速度和可靠性。此外,它们将调试复杂的构建问题从非常困难变为非常高效。
在构建系统的其他重要质量中,性能只是其中之一,例如依赖项管理和有效地处理多个存储库。查看 Gradle 和 Maven 之间的功能比较矩阵。
在决定构建系统时,牵引力和采用率也是重要的标准。毕竟,迁移构建是一项重要的决定,也是一项长期决定。Gradle 最近在所有开源项目中名列前 20 名。