繁体   English   中英

Scala通用类型慢

[英]Scala Generic Type slow

我确实需要创建一个用于比较Int或String或Char的方法。 由于没有用于<,>比较的方法,因此无法使用AnyVal。

但是,将其键入Ordered显示出明显的缓慢性。 有更好的方法来实现这一目标吗? 该计划是进行通用二进制排序,发现通用类型会降低性能。

def sample1[T <% Ordered[T]](x:T) = { x < (x) }
def sample2(x:Ordered[Int]) = { x < 1 }
def sample3(x:Int) = { x < 1 }

val start1 = System.nanoTime
sample1(5)
println(System.nanoTime - start1)
val start2 = System.nanoTime
sample2(5)
println(System.nanoTime - start2)
val start3 = System.nanoTime
sample3(5)
println(System.nanoTime - start3)
val start4 = System.nanoTime
sample3(5)
println(System.nanoTime - start4)
val start5 = System.nanoTime
sample2(5)
println(System.nanoTime - start5)
val start6 = System.nanoTime
sample1(5)
println(System.nanoTime - start6)

结果显示:

样本1:696122

样品2:45123

样本3:13947

样本3:5332

样品2:194438

样本1:497992

我在处理泛型时做错了方法吗? 或者在这种情况下,我应该使用使用Comparator的旧Java方法,示例如下:

object C extends Comparator[Int] {
  override def compare(a:Int, b:Int):Int = {
    a - b
  }
}
def sample4[T](a:T, b:T, x:Comparator[T]) {x.compare(a,b)}

如果要获得与生产环境类似的结果,请不要以这种方式进行微测试。 首先,您需要预热jvm。 之后,将您的测试作为多次迭代的平均值。 另外,由于const数据,您需要防止可能的jvm优化。 例如

def sample1[T <% Ordered[T]](x:T) = { x < (x) }
def sample2(x:Ordered[Int]) = { x < 1 }
def sample3(x:Int) = { x < 1 }
val r = new Random()


def measure(f: => Unit): Long = {
  val start1 = System.nanoTime
  f
  System.nanoTime - start1
}
val n = 1000000

(1 to n).map(_ => measure {val k = r.nextInt();sample1(k)})
(1 to n).map(_ => measure {val k = r.nextInt();sample2(k)})
(1 to n).map(_ => measure {val k = r.nextInt();sample3(k)})

val avg1 = (1 to n).map(_ => measure {val k = r.nextInt();sample1(k)}).sum / n
println(avg1)
val avg2 = (1 to n).map(_ => measure {val k = r.nextInt();sample2(k)}).sum / n
println(avg2)
val avg3 = (1 to n).map(_ => measure {val k = r.nextInt();sample3(k)}).sum / n
println(avg3)

我得到了结果,对我来说更有价值:

134
92
83

本书可以提供一些有关性能测试的信息。

Java Comparator的Scala等效项是Ordering 主要区别之一是,如果不手动提供,则编译器可以隐式注入适当的Ordering 默认情况下,将对ByteIntFloat和其他基元, OrderedComparable任何子类以及其他一些明显的情况执行此操作。

另外, Ordering提供了所有主要比较方法的方法定义作为扩展方法,因此您可以编写以下内容:

import Ordering.Implicits._

def sample5[T : Ordering](a: T, b: T) = a < b

def run() = sample5(1, 2)

从Scala 2.12开始,这些扩展操作(即a < b )调用包装在临时对象Ordering#Ops包装,因此代码将比使用Comparator慢。 在大多数实际情况下并不多,但是如果您关心微优化,那仍然很重要。

但是,您可以使用其他语法来定义隐式Ordering[T]参数并直接在Ordering对象上调用方法。 实际上,即使为以下两种方法生成的字节码也将是相同的(除了第三个参数的类型,以及相应compare方法的实现之外):

def withOrdering[T](x: T, y: T)(implicit cmp: Ordering[T]) = {
  cmp.compare(x, y) // also supports other methods, like `cmp.lt(x, y)`
}

def withComparator[T](x: T, y: T, cmp: Comparator[T]) = {
  cmp.compare(x, y)
}

实际上,当使用Int参数调用这些方法时,我的机器上的运行时是相同的。

因此,如果要比较Scala中的常规类型,通常应使用Ordering

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM