相比 Groovy 脚本, KTS 性能到底怎么样?

4,513 阅读5分钟

前言

大家肯定也都或多或少的写过一些Groovy代码,但由于不支持代码提示及编译时检查,使用Groovy开发的体验并不太好
Android Gradle插件4.0之后支持在Gradle构建配置中使用Kotlin 脚本 (KTS),用于替代 Groovy(过去在 Gradle 配置文件中使用的编程语言)。
KTSGroovy 更适合用于编写 Gradle 脚本,因为采用 Kotlin 编写的代码可读性更高,并且 Kotlin 提供了更好的编译时检查和 IDE 支持。

但是文档中也提到了,虽然与 Groovy 相比,KTS 当前能更好地在 Android Studio 的代码编辑器中集成,但采用 KTS 的构建速度往往比采用 Groovy 慢,因此在迁移到 KTS 时应考虑构建性能。

那么我们今天就来看下相比GroovyKTS性能到底怎么样?为大家决定是否迁移到KTS提供一定的参考

KTS性能分析

性能分析工具

要分析KTS的性能,我们首先需要稳定的测量编译的时间,编译速度可能受build cache等多种因素的影响,所以很难测量kts插件对性能的影响到底有多大

我们可以使用Gradle 性能剖析器来准确测量性能,这是一款用于收集 Gradle 构建的性能分析和基准化分析信息的工具。借助 Gradle性能剖析器,您可以创建构建场景并多次运行这些场景,以防止结果出现过大差异,并确保结果的可重现性。

基准化分析的部分项目设置配置包括:

  • 插件版本
  • Gradle 版本
  • JVM 设置(堆大小、永久代大小、垃圾回收等)
  • Gradle 工作器数量 (org.gradle.workers.max)
  • 按插件选项进一步优化性能

比如我们需要对clean build进行基准化分析,您可以创建一个gradle-profiler执行的场景:

# <root-project>/scenarios.txt
clean_build {
    tasks = [":app:assembleDebug"]
    cleanup-tasks = ["clean"]
}

如需运行此场景,请使用以下命令:

gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt

通过以上命令,就可以多次运行clean build,并生成clean build性能报告。除了clan buildgradle-profiler还可以针对增量编译,不同的 Gradle 插件版本,以及不同的内存/CPU 等执行性能分析。
通过gradle-profile命令,可以创建构建场景并多次运行,可以防止结果出现过大差异,并确保结果的可重现性,以帮助我们更好地分析性能。
关于gradle-profile的具体使用,可以参考文档:分析构建性能

Gradle 6.8 版本性能分析

针对Gradle 6.8版本,我们从以下4个用例来分析KTS性能

  • 首次运行(即清除所有build cache)
  • buildSrc abi 更改(支持的abi发生变化,可以理解为大多数缓存失效,大部分代码需要重新编译)
  • buildSrcabi 更改(即buildSrc中的普通修改)
  • 无改动

以下数据来自在Gradle CI上运行的性能测试。这些测试运行在一个包含大量subProject的大型项目中,并且它们在 GroovyKotlin DSL 上运行以进行比较。

Use caseGroovyKotlinDifferences
First use🟢 33.5s🔴 76.2sGroovy DSL is 2.2x faster
buildSrc abi change🟢 13.2s🔴 42.3sGroovy DSL is 3.2x faster
buildSrc non-abi change🔴 13s🟢 5.2sKotlin DSL is 2.5x faster
Nothing changes🔵 1.7s🔵 1.8sSimilar performance

可以看出,Groovy脚本在性能上还是有一定优势

  1. 在首次运行时,Groovy DSLKTS2.2
  2. buildSrc abi更改时,Groovy DSLKTS3.2
  3. buildSrcabi更改时,KTSGroovy2.5
  4. 在代码没有发生更改时,两者性能类似

可以看出,KTS只有在buildSrcabi更改时有性能优势,这是因为buildSrc中的groovy的更改会导致整个项目过时,导致项目重新编译
buildSrc中的kts修改可以跳过未受影响的构建脚本文件的编译,因此当修改buildsrc时,kts编译会远比groovy插件要快

以上数据来源于:builds.gradle.org/buildConfig…,可以使用访客模式登录查看

Gradle 7.4 版本性能分析

针对Gradle 7.4版本,我们通过以下3个用例来分析KTS性能

  • 首次运行(即清除所有build cache)
  • buildSrc abi 更改(支持的abi发生变化,可以理解为大多数缓存失效,大部分代码需要重新编译)
  • buildSrcabi 更改(即buildSrc中的普通修改)
Use CaseGroovyKotlinDifference
First use🟢 38.855s🔴 63.54sGroovy DSL is 1.6x faster
buildSrc abi change🟢 25.307🔴 35.014sGroovy DSL is 1.4x faster
buildSrc non-abi change🔴 24.526s🟢 4.732sKotlin DSL is 5x faster

可以看出,针对Gradle 7.4版本,KTS的编译性能有一定改善,性能差距减少到了1.5倍左右

总结

总得来说,KTS在可读性,易用性,编译时检查与IDE支持等方面比起Groovy都有巨大的优势,但是在性能方面存在一定劣势,具体如下:

  • 针对Gradle 6.8版本,如果缓存大部分失效或者没有缓存,Groovy DSLKTS23
  • Gradle 7.4版本KTS性能有一定改善,如果缓存大部分失效或者没有缓存,Groovy DSLKTS1.5倍左右。
  • buildSrc中发生非abi更改时,kts脚本编译比Groovy DSL45倍,这是因为buildSrc中的kts可以跳过未受影响的构建脚本的编译,而groovy暂不支持
  • 当项目没有发生更改时,KTSGroovy DSL的编译速度相差不大

由上可知,KTS目前的优缺点都非常明显,在易用性上非常突出,在性能方面有一定劣势,Gradle官方也一直在优化中,读者可以根据自己的项目情况决定是否将构建配置从 Groovy 迁移到 KTS

参考资料

The Kotlin and Groovy DSLs should have similar performance characteristics