我确实需要创建一个比较Int或String或Char的方法。使用AnyVal是不可能的,因为没有方法可用于<,>比较。
然而,将其键入Ordered会显示出明显的缓慢。有没有更好的方法来实现这一目标?计划是进行通用二进制排序,发现通用类型会降低性能。
sbt test
结果显示:
的Sample1:696122
样品2:45123
样品3:13947
样品3:5332
样品2:194438
的Sample1:497992
我是否采用不正确的方式处理泛型?或者我应该在这种情况下使用旧的Java方法来使用Comparator,样本如下:
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)
答案 0 :(得分:2)
如果你想获得与生产环境相似的结果,不要以这种方式进行微观测试。 首先,你需要热身jvm。之后,将您的测试作为多次迭代的平均值。此外,由于const数据,您需要防止可能的jvm优化。 E.g。
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
This本书可以为性能测试提供一些启示。
答案 1 :(得分:2)
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
。