dzi*_*iki 1 optimization sequence kotlin kotest
我是序列的新手,所以我可能做了一些(或多或少)非常错误的事情,但我有一个问题:
我写了两个函数:
fun isPrimeNumber1(number: Int): Boolean {
if (number <= 1) return false
for (divider in 2 .. number / 2) {
if ( number % divider == 0 ) return false
}
return true
}
Run Code Online (Sandbox Code Playgroud)
和
fun isPrimeNumber2(number: Int): Boolean {
if (number <= 1) return false
return !(2 .. number / 2).asSequence().map { it }.any { number % it == 0 }
}
Run Code Online (Sandbox Code Playgroud)
现在我正在运行一个用 编写的测试kotest,其中两个函数都接收Int.MAX_VALUE为number.
class MyTestPrime : FunSpec({
context("Prime numbers") {
test("Should return true if number is prime (1st fun)") {
isPrimeNumber1(Int.MAX_VALUE) shouldBe true
}
test("Should return true if number is prime (2nd fun)") {
isPrimeNumber2(Int.MAX_VALUE) shouldBe true
}
}
})
Run Code Online (Sandbox Code Playgroud)
该isPrimeNumber1()函数的执行时间约为 3.5 秒,第二个函数的执行时间isPrimeNumber2()约为 8.5 秒。
为什么呢?我是否遗漏了一些关于序列的信息?或者也许我的代码以正确但非常不理想的方式完成了它的目的?
这是预期的。带有序列的变体创建一个Iterator对象,并为每个元素调用.hasNext()和.next()函数。
由于 anIterator与对象而不是基元一起工作,因此您所有的ints 都通过Integer::valueOf调用进行装箱。(注意:.map { it }步骤是多余的)。
我通过 IntelliJ Idea 中的 Java Flight Recorder 运行了这两个函数,我们可以看到,与其他变体相比,序列变体导致了更多的函数调用。
isPrimeNumber1:
isPrimeNumber2:
如您所见,该isPrimeNumber2变体导致在后台调用更多函数,因此受到其开销的影响。
检查它的另一种方法是将两个函数的字节码反编译为 Java。它可以让您更好地了解幕后发生的事情。这是反编译的两个函数(再次使用 IntelliJ):
private static final boolean isPrimeNumber1(int number) {
if (number <= 1) {
return false;
} else {
int divider = 2;
int var2 = number / 2;
if (divider <= var2) {
while (true) {
if (number % divider == 0) {
return false;
}
if (divider == var2) {
break;
}
++divider;
}
}
return true;
}
}
private static final boolean isPrimeNumber2(int number) {
if (number <= 1) {
return false;
} else {
byte var1 = 2;
Sequence $this$any$iv =
SequencesKt.map(
CollectionsKt.asSequence((Iterable) (new IntRange(var1, number / 2))),
(Function1) null.INSTANCE);
int $i$f$any = false;
Iterator var3 = $this$any$iv.iterator();
boolean var10000;
while (true) {
if (var3.hasNext()) {
Object element$iv = var3.next();
int it = ((Number) element$iv).intValue();
int var6 = false;
if (number % it != 0) {
continue;
}
var10000 = true;
break;
}
var10000 = false;
break;
}
return !var10000;
}
}
Run Code Online (Sandbox Code Playgroud)
最后说明:正如其他人提到的,要获得有意义的性能测量,您需要使用类似jmh. 然而,根据经验,更简单的语言结构,例如一个序列上的常规 for/while 循环,由于它们提供的抽象级别较低,因此往往具有较少的开销。
| 归档时间: |
|
| 查看次数: |
293 次 |
| 最近记录: |