kotlin java 效率_Java与Kotlin - 性能

差不多一年前,我是波兹南理工大学软件工程专业的学生,​​考虑硕士论文题目。所有推荐的主题似乎都很无聊或者完全超出了我的兴趣范围,因此我决定提出自己的研究主题。

大约在同一时间,10月份,我和来自RSQ Technologies的朋友们前往阿姆斯特丹的KotlinConf 2018会议。我们参加了由Kotlin社区众多有趣人士组成的闭幕小组。其中一个是威廉姆库克。德克萨斯大学的教授提到Kotlin在科学界没有大​​量的观众,因为没有很多关于Kotlin的论文。所以我问自己 - 也许我可以用它做点什么并尝试写一些关于Kotlin的东西?

几天后,在会议结束后,我在家里冷静地追赶KotlinConf的老谈话。我遇到了Duncan McGregor关于缩小Kotlin代码大小和执行时间的一个很棒的“ Kotlin语言特性的成本”。这促使我深入了解性能并在Java和Kotlin之间建立差异。

所以,几个月后,我是一名硕士研究生,试图在这篇中篇文章中总结我的实验和结果。我希望你会喜欢它,并了解一些新的东西。

研究问题

首先,我想与大家分享我的硕士论文研究问题。其中有两个,但在第一篇文章中,我们将重点关注第一个 - 与性能相关联。

RQ:使用Java Runtime Environment,Kotlin和Java中相同基准测试的各种实现之间的执行性能是否存在显着差异?

计算机语言基准游戏

动态指标比较将基于最受欢迎的跨语言基准套件之一 - 计算机语言基准游戏(CLBG)传播的想法。

由Doug Bagley于2000年推出,作为The Great Computer Language Shootout项目,旨在比较所有主要语言。如今,该项目发展成为计算机语言基准游戏,这是科学上最流行的跨语言基准。随着新问题基准测试和语言实现,项目总是在不断发展。它由创建者系统地更新,以遵循编程市场趋势(通过添加新语言,删除不再使用的语言并更新基准算法列表进行测试)。

CLBG基准测试背后的目标- 回答以下问题,由4chan用户之一询问:

我的问题是,如果这里的任何人都有过简单基准测试的经验,可以告诉我要测试哪些内容,以便简单了解每种语言的一般性能?

为了回答这个问题,CLBG提出了一组10个不同的算法问题。所有问题都在官方网页上公布和描述。引入的算法对如何实现它们有严格的规则,算法使用什么来实现正确的等效结果。通过以下信息,可以使用将要测量的特定语言来实现问题。

为了对结果进行客观比较,CLBG基准测试总是使用固定脚本来实现所有实验的指标。收集的测量值与所示语言中的算法的实现无关。

基准选择

在实验开发过程中,计算机语言基准游戏由10个基准程序组成(旁注:CLBG中的基准数量随时间变化)。他们每个人都提出了一种不同类型的问题,它们使用不同的语言范式,语言特征和方法来解决它们。

(我不打算在CLBG中描述每个基准,如果您有兴趣,我建议您阅读网页上的信息)

这个实验背后的主要想法是比较Java和Kotlin。为实现这一目标,该实验使用了Java程序的基本实现(取自CLBG基准测试库)和Kotlin中的两个实现 - 转换和惯用(在下一节中描述)。

根据这些假设,实验中使用的基准是基于两个因素选择的:

从CLBG存储库获取的最佳Java实现必须可转换为Kotlin语言

程序必须尽可能多地操作数据

的作者“JVM托管语言:他们谈谈话,但是他们向前走?”的论文提出的指示节目是否大多操纵整数,浮点数,指针或字符串区分的方案CLBG语料库的方法。这些信息将帮助我们将基准分成不同的组。

考虑到所有因素,最终实验中只使用了6个CLBG基准测试。十个基准测试中有四个被拒绝,以便与Java代码必须可转换为Kotlin语言而不需要对代码进行大量更改的假设保持一致。

int - 整数

fp - 浮点

ptr - 指针

str - string

表1:选定的基准,包含大多数操纵数据的信息

备注

在基准选择之后(如表1所示),最终的完整基准测试套件不包含主要操作字符串资源的程序。

实现

本实验中每个基准测试有三种实现方式。

Java

Kotlin-converted

Kotlin-idiomatic

所有这些代码都用于实验 - 由外部Python脚本编译,执行和测量。没有任何实现具有可能干扰最终结果的任何测量或不相关的代码部分。

Kotlin分为两个版本。我想检查多个Kotlin实现之间的区别。我假设Kotlin转换可能是具有与Java版本类似的性能和字节码结果的代码。另一方面,我使用Kotlin-idiomatic实现来获得更有可能由经验丰富的Kotlin程序员生成的代码的基准测试结果。

Java实现

所有Java代码都直接取自计算机语言基准测试游戏库中提供的大多数实际基准测试实现,而不对其进行任何更改。

在基准测试库中,有多个版本的Java基准测试。根据CLBG网页上提供的排行榜,实验中使用的代码是获得最佳结果的代码。

Kotlin-converted

使用IntelliJ IDEA提供的Java到Kotlin转换器创建实现。对原始转换版本进行了多处更改,以使代码处于可执行状态。大多数更改都是允许编译器运行代码所必需的。

所有Kotlin转换的实现都有一个引入代码的更改。为了使用命令行界面编写代码,方法main()被提取到原始文件类之外。

Kotlin-idiomatic

引入Kotlin-idiomatic实现的更改主要基于:

成语 - 列出Kotlin经常使用的习语。该网站是官方Kotlin文档的一部分

编码约定 - 包含当前推荐的Kotlin语言编码风格。该页面也是Kotlin文档的一部分

IDEA默认代码检查

Kotlin惯用实现基于转换后的版本。

备注

六个基准测试中有五个使用Threads(Java和Kotlin实现)并行工作,Kotlin实现都没有使用协同程序,使用它们会显着影响性能结果

语言版本和硬件

有关用于基准执行的软件和硬件环境的强制性信息。

实验在硬件环境中执行,详细信息如表2所示 .Linux Ubuntu系统的选择取决于推荐的操作系统用于CLBG指标测量脚本。

表3列出了用于执行基准实现的Java和Kotlin版本。这两个版本代表了当时最新的语言版本。

备注

所有基准测试都在Oracle HotSpot VM上完成

动态指标

所以是的,我在动态指标比较中真正衡量的是什么?

我决定使用大多数指标来比较语言,这些指标通常被认为对程序员来说是最重要的:

执行时间处理时间

内存使用情况

CPU负载

每个程序都执行并测量了500次。

基准指标也基于计算机语言基准游戏中使用的指标。所有程序都使用专用的CLBG脚本执行和测量。

在Kotlin和Java基准测试套件开发过程中实验了多种测量方法,并且仍然可以在存储库中使用。最初,使用Java / Kotlin代码测量时间,使用来自System类的currentTimeMilis()或nanoTime()等方法,但这个想法在进一步的工作中被放弃了。结果有很大的差异,后来我决定放弃这种测量方法。根据环境的不同,测量其他负载指标(如CPU和内存)也不是直截了当且受各种因素的影响(深入研究基准测量方法是另一篇长篇文章的主题!)。

所有这些工作导致决定在这种情况下应用官方CLBG测量脚本将是最客观的方法。该方法可以帮助将所有Kotlin测量结论放在CLBG基准所呈现的不同语言评估结果的背景下。

CLBG测量页面提供了Python脚本如何测量每个参数的详细信息。

结果

项目存储库中提供了每个基准测试的完整测量结果列表。

执行时间处理时间

下图显示了每个基准测试和每个实现的执行时间框图。括号中的字母表示大多数操纵数据。

内存使用情况

下图显示了每个基准测试和每个实现的内存消耗框图。括号中的字母表示大多数操纵数据。

CPU负载

下表显示了每个基准测试和每个实现中每个CPU内核的CPU负载。

结论

下表显示了基准结果与中位数内存消耗和中位执行时间的比较。括号中的字母代表大多数操纵数据。

引人注目的第一件事是,Kotlin-idiomatic实现从未在任何测量中值中获得最佳结果。在这种情况下,中位执行时间高于其他实现。内存消耗也是如此:惯用实现有时处于第二位,但从未达到给定基准的最佳结果。因此,我们可以得出结论,使用推荐技术编写Kotlin代码可能不是那些寻求内存管理和最快执行时间的最佳结果的人的最佳选择。

基于这些结果,我们还可以假设,Java实现通常更好地管理内存优化和程序执行。Java实现在六个基准中的四个中执行更好的中值执行时间。相同的实现也在六个基准测试中的四个中实现了最佳的中值内存使用率。Kotlin-converted的测量结果显示Mandelbrot和Fannkuch Redux的执行时间更短,Fasta和Binary Trees基准测试中的内存消耗更低。

在二叉树基准测试中,最高和最低中值执行时间之间的最大差异是显而易见的。最佳执行时间(Java)和最差(Kotlin-idiomatic)之间的差异在6.76%的水平。还有基准测试,Java,Kotlin-converted和惯用实现实现了非常相似的结果。在Spectral Norm和Mandelbrot中,最高和最低中位执行时间之间的差异小于1%。

在Fannkuch Redux基准测试中可以看到相当大的内存使用测量结果变化。如前所述,Fannkuch Redux是一个主要操纵整数的程序。Java和Kotlin管理整数的方式有很大的不同。在Java中,没有小数分量的数字大多数保存为基本类型,与Kotlin相反,Kotlin必须将所有这些数字装箱为Integer对象。

在图3中,我们可以看到Kotlin-converted的实现具有比其他实现低得多的中值内存消耗。内存使用中位数之间的差异甚至超过100MB。针对本论文进行的研究没有为观察到的结果提供明确的解释,因为即使是静态字节码分析结果也没有任何显着的变化,有利于Kotlin-converted的实现。

另一方面,我们有最后的动态指标结果 - CPU负载。如前一节所述,特定测量之间没有显着差异。考虑到任务被随机分配给CPU内核,在大多数情况下,实现之间的差异不高于3%。由于计算机硬件和软件的不同,这种差异在执行之间会有所不同。用各种语言实现的基准测试之间的差异可能要高得多。在官方CLBG基准网页上可以获得具有更显着差异的CPU负载结果数量。

有了所有这些信息,我们可以假设两种语言都以类似的方式加载CPU。在任何这些语言或实现中,CPU负载没有显着降低。

那么......研究问题的答案是什么?

在本文开头,我提出了我的研究问题。当我们根据取得的成果形成答案时,我们来到了这个地方。

RQ:使用Java Runtime Environment,Kotlin和Java中相同基准测试的各种实现之间的执行性能是否存在显着差异?

从执行时间的角度来看,最高和最低中值经过时间之间的最大差异可以从6.7%到Java实现二进制树基准测试,到1.2%有利于Kotlin-converted实现Fannkuch Redux基准测试。Kotlin-idiomatic实现没有达到最佳中位执行时间的基准。Java代码在六个基准测试中的四个中达到最佳时间中位数,其余基准测试对于Kotlin-converted的代码表现最佳。

在六个基准测试中的四个基准测试中,内存消耗比较似乎是Java实现中最低的。此外,接下来的两个是Kotlin-converted代码。两种实现的最佳内存消耗结果与这些代码的最佳执行时间结果不重叠。内存管理可以为不同基准测试中的语言提供非常多样化的值。Java实现在Fannkuch Redux中实现了更好的内存使用率,即使是13%,但另一方面,与Java结果相比,Kotlin-converted后二叉树的转换率提高了9.7%。

CPU负载测量结果表明,这两种语言之间的核心负载管理没有明显区别。所有基准测试实现的结果与错误级别的差异非常相似。

下一步是什么?

这就是动态指标。我不是统计和数据分析专家,所以我可能没有提出大量的结论,但它们隐藏在这些结果中。如果有人有兴趣 - 我很乐意看到有人根据我的数据向我展示更多分析。

此外,如果您在我的比较中发现任何错误 - 错误的实施,中位数评估等 - 在评论部分,Twitter或官方Kotlin松弛(Jakub Aniola)中打击了我。

在下一部分中,我将介绍“Java vs Kotlin”静态分析的方法和结果。我认为下次我们应该从不同的角度来看待这两种语言之间的差异。JVM字节码透视图。

感谢Paulina Sielicka 和Aleksander Sadaj 。

你可能感兴趣的:(kotlin,java,效率)