介绍
在2018年Code Advent挑战赛中,我解决了Groovy中的所有难题。 显而易见,选择良好的数据结构对于获得高性能的解决方案最为重要。 但是,至少在使用Groovy时,我们迭代这些结构的方式也非常重要。
衡量绩效
我想测量求和一些数字所需的时间。 为了测试循环的性能,我准备了一个小函数,将一些数字简单地求和:
void printAddingTime(String message, long to, Closure<Long> adder) {
LocalTime start = LocalTime.now()
long sum = adder(to)
println("$message: $sum calculated in ${Duration.between(start, LocalTime.now()).toMillis()} ms")
}
用于求和函数的伪代码如下:
for i = 1 to n
for j = 1 to n
sum += i * j
end
end
循环类型
让我们以各种方式实现求和功能。
第一个循环型是使用内置(通过Groovy中)功能collect
和sum
上集合( Range
是本示例):
(1..n).collect { long i ->
(1..n).collect { long j ->
i * j
}.sum()
}.sum()
each
接下来,让我们用写相同功能的each
内置功能上集合( Range
是本示例),然后添加结果累加器变量:
long sum = 0
(1..n).each { long i ->
(1..n).each { long j ->
sum += i * j
}
}
return sum
times
现在,可以使用Groovy内置于Number
的函数times
来代替使用each
函数:
long sum = 0
n.times { long i ->
n.times { long j ->
sum += (i + 1)*(j+1)
}
}
return sum
我们必须在i
和j
上加1
,因为时间会生成从0
到n
数字(不包括数字)。
Java 8附带了一个新功能–流。 流的一个示例是LongStream
。 幸运的是,它具有sum
内置函数,我们可以使用:
LongStream.range(0, n).map { i ->
LongStream.range(0, n).map { j ->
(i + 1) * (j + 1)
}.sum()
}.sum()
LongStream
生成数字与times
函数的方式相同,因此我们还必须在此处将i
和j
加1
。
带手动求和的
代替LongStream
上的sum
函数,我们可以手动将所有数字相加:
long sum = 0
LongStream.range(0, n).forEach { i ->
LongStream.range(0, n).forEach { j ->
sum += (i + 1) * (j + 1)
}
}
return sum
while
当然,由于Groovy从Java继承了大部分语法,因此我们可以使用while
循环:
long sum = 0
long i = 1
while(i <= n){
long j = 1
while(j <= n){
sum+= i*j
++j
}
++i
}
return sum
for
正如我们可以使用while
,我们也可以在Groovy中使用for
循环:
long sum = 0
for (long i = 1; i <= n; ++i) {
for (long j = 1; j <= n; ++j) {
sum += i * j
}
}
return sum
结果
我的测试在Java 1.8
和Groovy 2.5.5
上运行。 使用bash脚本触发了脚本loops.groovy
:
#!/bin/sh
for x in 10 100 1000 10000 100000; do
echo $x
groovy loops.groovy $x
echo
done
值以毫秒为单位
循环n | 10 | 100 | 1000 | 10000 | 100000 |
---|---|---|---|---|---|
collect + sum | 7 | 22 | 216 | 16244 | 1546822 |
each | 12 | 17 | 118 | 7332 | 706781 |
times | 2 | 10 | 109 | 8264 | 708684 |
LongStream + sum | 7 | 17 | 127 | 7679 | 763341 |
LongStream +手动求和 | 18岁 | 35 | 149 | 6857 | 680804 |
while | 8 | 20 | 103 | 3166 | 301967 |
for | 7 | 10 | 25 | 359 | 27966 |
如您所见,使用内置Groovy函数进行少量迭代就足够了,但是对于大量迭代,我们应该使用while
或for
循环,例如在普通的旧Java中。
给我看代码
这些示例的代码在此处提供 。 您可以在计算机上运行这些示例,并自行检查性能。
翻译自: https://www.javacodegeeks.com/2019/01/loops-performance-groovy.html