kotlin - 为什么标准迭代器比Kotlin中的序列要快?

标签 kotlin optimization sequence 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
}
fun isPrimeNumber2(number: Int): Boolean {
    if (number <= 1) return false
    return !(2 .. number / 2).asSequence().map { it }.any { number % it == 0 }
}
现在,我正在运行一个用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
        }
    }
})
isPrimeNumber1()函数的执行时间约为3.5秒,而第二个函数isPrimeNumber2()的执行时间约为8.5秒。
为什么呢?我是否缺少有关序列的信息?还是我的代码以正确但非常不理想的方式实现了它的目的?

最佳答案

可以预料的。具有序列的变量创建一个Iterator对象,并为每个元素调用.hasNext().next()函数。
由于Iterator适用于对象而不适用于基元,因此所有int都会通过Integer::valueOf调用进行装箱。 (注意:.map { it }步骤是多余的)。
我通过IntelliJ Idea中的Java Flight Recorder运行了这两个函数,并且可以看到,与另一个变体相比,序列变体导致更多的函数调用。
isPrimeNumber1:
isPrimeNumber1
isPrimeNumber2:
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;
  } 
}
最后说明:如其他人所述,要获得有意义的性能评估,您需要使用jmh之类的工具。但是,根据经验,较简单的语言构造(例如,序列上的常规for / while循环)由于其提供的抽象级别较低而倾向于具有较少的开销。

关于kotlin - 为什么标准迭代器比Kotlin中的序列要快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64413369/

相关文章:

db2 - 在 DB2 中将序列递增两次

php - Web 服务器如何处理请求?

kotlin - 接口(interface)作为 Kotlin 中类的依赖项是什么意思?

kotlin - 在 Kotlin 中无需公开具体类型的通用生产者和消费者

c++ - 使用 std::accumulate 和 std::string 有效

R - 基于重复序列的子数据帧

java - list 的迭代器同时实现了 Kotlin.Collection.Iterator 和 Java.util.Iterator?

Kotlin - 泛型函数引用

java - 用于了解 Java 程序性能的 Eclipse 插件

Python 优化程度(公共(public)子表达式消除)