[英]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
。 默认情况下,将对Byte
, Int
, Float
和其他基元, Ordered
或Comparable
任何子类以及其他一些明显的情况执行此操作。
另外, 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.