Performance 为什么是Scala;对于循环理解“;与FOR循环相比非常慢?

Performance 为什么是Scala;对于循环理解“;与FOR循环相比非常慢?,performance,scala,for-loop,Performance,Scala,For Loop,据说用于理解的Scala实际上相当慢。我给出的理由是,由于Java的限制,对于理解(如下面使用的“reduce”),需要在每次迭代中生成一个临时对象,以便调用传入的函数 这是真的吗?下面的测试似乎证明了这一点,但我不完全理解为什么会这样 这可能对“lambdas”或匿名函数有意义,但对非匿名函数没有意义 在我的测试中,我对list.reduce运行了循环(见下面的代码),发现它们的速度是原来的两倍多,即使每次迭代调用的函数与传递给reduce的函数完全相同 我发现这与直觉背道而驰(曾经有人认为S

据说用于理解的Scala实际上相当慢。我给出的理由是,由于Java的限制,对于理解(如下面使用的“reduce”),需要在每次迭代中生成一个临时对象,以便调用传入的函数

这是真的吗?下面的测试似乎证明了这一点,但我不完全理解为什么会这样

这可能对“lambdas”或匿名函数有意义,但对非匿名函数没有意义

在我的测试中,我对list.reduce运行了循环(见下面的代码),发现它们的速度是原来的两倍多,即使每次迭代调用的函数与传递给reduce的函数完全相同

我发现这与直觉背道而驰(曾经有人认为Scala库会被精心创建为尽可能最佳)

在我做的一个测试中,我以五种不同的方式运行了相同的循环(将数字加起来1到100万,不考虑溢出):

  • 值数组上的for循环
  • for循环,但调用函数而不是内联算术
  • 对于循环,创建包含加法函数的对象
  • list.reduce,传递一个匿名函数
  • list.reduce,传入对象成员函数
  • 结果如下: 测试:最小/最大/平均(毫秒)

    1。27/157/64.78
    
    2.27/192/65.77关于“理解”的说法是正确的,但你的问题是,你把“理解”和“匿名函数”混为一谈了

    Scala中的“用于理解”是一系列
    .flatMap
    .map
    .filter
    应用程序的语法糖。由于您正在测试简化算法,并且无法使用这三个函数实现简化算法,因此您的测试用例是不正确的

    下面是一个“理解”的例子:

    然后,它将取消匿名函数语法:

    val result =
      listOfLists.flatMap(
        new Function1[List[Int], List[Int]] {
          override def apply(itemOfListOfLists: List[Int]): List[Int] =
            itemOfListOfLists.map(
              new Function1[Int, Int] {
                override def apply(itemOfItemOfListOfLists: Int): Int =
                  itemOfItemOfListOfLists + 1
              }
            )
        }
      )
    

    从desugarred代码中可以明显看出,
    Function1[Int,Int]
    类在每次调用
    apply(itemoflists:List[Int]):List[Int]
    方法时都会被实例化。这会发生在列表的每个条目上。因此,你的理解越复杂,你得到的
    函数
    对象的实例化就越多。

    .reduce
    与“for comprehensions”无关作为旁注,scala编译器插件旨在消除常见情况下的这种开销:。但我自己并没有尝试过。事实上,您的前3个测试用于理解,您正在将这些测试的时间与
    reduce
    进行比较。@RégisJean Gilles::ScalaCL旨在(回到Scala 2.9)生成OpenCL的代码,即:在GPU上运行的代码。特别是,您还可以告诉它完成它的工作,但是为CPU(而不是GPU)生成代码。它工作得很好,但不幸的是,它在很大程度上是基于宏的,宏在Scala中移动目标,从一个版本切换到另一个版本。ScalaCL在Scala的最新版本中不可用。当我写评论Scala2.10刚刚发布时。scalaCL被明确宣传为一种加速循环的方法(除了它的OpenCL功能之外)。我引述:“它还经常以很大幅度优化常规Scala循环(在数组、列表和内联范围上),因此即使您不关心OpenCL,您也会希望使用它”。作为旁注,它是/曾经是一个编译器插件,而不是一组宏(尽管我想这是一个没有意义的观点,因为它更依赖于实现细节,因此更不可靠)。
    class t(val i: Int) {
        def summit(j: Int) = j + i
    }
    
    object bar {
        val biglist:List[Int]  =  (1 to 1000000).toList
    
        def summit(i: Int, j:Int) = i+j
    
        // Simple for loop
        def forloop:  Int = {
            var result: Int = 0
            for(i <- biglist) {
                result += i
            }
            result
        }
    
        // For loop with a function instead of inline math
        def forloop2:  Int = {
            var result: Int = 0
            for(i <- biglist) {
                result = summit(result,i)
            }
            result
        }
    
        // for loop with a generated object PER iteration
        def forloop3: Int = {
            var result: Int = 0
            for(i <- biglist) {
                val t = new t(result)
                result = t.summit(i)
            }
            result
        }
    
        // list.reduce with an anonymous function passed in
        def anonymousfunc: Int = {
            biglist.reduce((i,j) => {i+j})
        }
    
        // list.reduce with a named function
        def realfunc: Int = {
            biglist.reduce(summit)
        }
    
        // test calling code excised for brevity. One example given:
        args(0) match {
            case "1" => {
                        val start = System.currentTimeMillis()
                        forloop
                        val end = System.currentTimeMillis()
                        println("for="+(end - start))
                        }
             ...
    }
    
    val listOfLists = List(List(1,2), List(3,4), List(5))
    val result = 
      for {
        itemOfListOfLists <- listOfLists
        itemOfItemOfListOfLists <- itemOfListOfLists
      }
      yield (itemOfItemOfListOfLists + 1)
    assert( result == List(2,3,4,5,6) )
    
    val result =
      listOfLists.flatMap(
        itemOfListOfLists => itemOfListOfLists.map(
          itemOfItemOfListOfLists => itemOfItemOfListOfLists + 1
        )
      )
    
    val result =
      listOfLists.flatMap(
        new Function1[List[Int], List[Int]] {
          override def apply(itemOfListOfLists: List[Int]): List[Int] =
            itemOfListOfLists.map(
              new Function1[Int, Int] {
                override def apply(itemOfItemOfListOfLists: Int): Int =
                  itemOfItemOfListOfLists + 1
              }
            )
        }
      )