Performance 功能性进近比Kotlin中的顺序进近慢100倍?

Performance 功能性进近比Kotlin中的顺序进近慢100倍?,performance,kotlin,functional-programming,Performance,Kotlin,Functional Programming,所以我又拿起了Euler项目和Kotlin玩了一会儿。对于那些不了解ProjectEuler的人来说,它是一个编程练习从平庸到相当困难的网站 无论如何,第一个问题是: 如果我们列出10以下的所有自然数,它们是3或5的倍数,我们得到3、5、6和9。这些倍数之和是23 求1000以下所有3或5的倍数之和 我从顺序和功能上解决了这个问题,因为我想看看它们之间的比较: class ProjectEuler1 { companion object { fun sequential

所以我又拿起了Euler项目和Kotlin玩了一会儿。对于那些不了解ProjectEuler的人来说,它是一个编程练习从平庸到相当困难的网站

无论如何,第一个问题是:

如果我们列出10以下的所有自然数,它们是3或5的倍数,我们得到3、5、6和9。这些倍数之和是23

求1000以下所有3或5的倍数之和

我从顺序和功能上解决了这个问题,因为我想看看它们之间的比较:

class ProjectEuler1 {
    companion object {

        fun sequential(): Int {
            var sum = 0
            for (i in 1..999)
                if (i % 3 == 0 || i % 5 == 0)
                    sum += i
            return sum
        }

        fun functional(): Int = (1..999).filter { it % 3 == 0 || it % 5 == 0 } .sum()

        fun benchmark() {

            var solSequential = -1
            val tSequential = measureExactTimeMillis { solSequential = sequential() }

            var solFunctional = -1
            val tFunctional = measureExactTimeMillis { solFunctional = functional() }

            println("""
                +---
                |${this::class.java.canonicalName.replace(".Companion", "")}
                +---
                |Sequential solution: $solSequential
                |Sequential running time: ${tSequential.round(6)} ms
                +---
                |Functional solution: $solFunctional
                |Functional running time: ${tFunctional.round(6)} ms
                +---
            """.trimIndent())

        }
    }
}
measureExactTimeMillis
只是
measureNanoTime
除以
1\u 000
返回一个
Double

无论如何,运行几次后,输出总是或多或少如下:

+---
|ProjectEuler1
+---
|Sequential solution: 233168
|Sequential running time: 0.6097 ms
+---
|Functional solution: 233168
|Functional running time: 33.3555 ms
+---
顺序版本比简单的功能实现快50-100倍,遗憾的是更详细


这是什么原因?性能是否至少应该具有可比性(相对于数量级的差异)?我错过了优化函数实现应该做的事情了吗?

我猜测为什么函数版本会慢一些:装箱/取消装箱的原语和创建中间
列表
@Slaw的组合我认为kotlin函数的编译类似于Java streams,Java streams可以在在每一步之后,背景是延迟计算,而不是急切的收集。为
Iterable
提供的扩展函数是急切的,并返回中间Iterable。Java streams的Kotlin等价物,或至少接近等价物是。@Slaw我在几分钟前也发现了这一点,但在筛选器之前添加
.asSequence()
,使操作花费的时间延长了10-20%。当然,这都是关于装箱/取消装箱和额外的集合。JVM对具有基元类型的操作进行了大量优化,而对装箱类型则没有。在顺序代码中,您只需使用primitive
int
作为迭代器,对
执行一个简单的
循环,在“函数”代码中,您创建一个装箱的
整数
列表
,并使用
迭代器对其进行迭代。序列可以帮助您避免额外的集合,但它们是通用的,因此装箱/取消装箱将保持不变。