简体   繁体   English

Scala通用类型慢

[英]Scala Generic Type slow

I do need to create a method for comparison for either Int or String or Char. 我确实需要创建一个用于比较Int或String或Char的方法。 Using AnyVal was not make it possible as there were no method's for <, > comparison. 由于没有用于<,>比较的方法,因此无法使用AnyVal。

However Typing it into Ordered shows a significant slowness. 但是,将其键入Ordered显示出明显的缓慢性。 Are there better ways to achieve this? 有更好的方法来实现这一目标吗? The plan is to do a generic binary sorting, and found Generic typing decreases the performance. 该计划是进行通用二进制排序,发现通用类型会降低性能。

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)

The results shows: 结果显示:

Sample1:696122 样本1:696122

Sample2:45123 样品2:45123

Sample3:13947 样本3:13947

Sample3:5332 样本3:5332

Sample2:194438 样品2:194438

Sample1:497992 样本1:497992

Am I doing the incorrect way of handling Generics? 我在处理泛型时做错了方法吗? Or should I be doing the old Java method of using Comparator in this case, sample as in: 或者在这种情况下,我应该使用使用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)}

Do not do micro-tests in such way if you want to get results somehow similar you will have in production env. 如果要获得与生产环境类似的结果,请不要以这种方式进行微测试。 First of all you need to warm-up jvm. 首先,您需要预热jvm。 And after that do your test as average of many iterations. 之后,将您的测试作为多次迭代的平均值。 Also, you need to prevent possible jvm optimizations because of const data. 另外,由于const数据,您需要防止可能的jvm优化。 Eg 例如

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)

I got results, which look more fare for me: 我得到了结果,对我来说更有价值:

134
92
83

This book could give some light on performance tests. 本书可以提供一些有关性能测试的信息。

The Scala equivalent of Java Comparator is Ordering . Java Comparator的Scala等效项是Ordering One of the main differences is that, if you don't provide one manually, a suitable Ordering can be injected implicitly by the compiler. 主要区别之一是,如果不手动提供,则编译器可以隐式注入适当的Ordering By default, this will be done for Byte , Int , Float and other primitives, for any subclass of Ordered or Comparable , and for some other obvious cases. 默认情况下,将对ByteIntFloat和其他基元, OrderedComparable任何子类以及其他一些明显的情况执行此操作。

Also, Ordering provides method definitions for all the main comparison methods as extension methods, so you can write the following: 另外, Ordering提供了所有主要比较方法的方法定义作为扩展方法,因此您可以编写以下内容:

import Ordering.Implicits._

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

def run() = sample5(1, 2)

As of Scala 2.12, those extension operations (ie, a < b ) invoke wrapping in a temporary object Ordering#Ops , so the code will be slower than with a Comparator . 从Scala 2.12开始,这些扩展操作(即a < b )调用包装在临时对象Ordering#Ops包装,因此代码将比使用Comparator慢。 Not much in most real cases, but still significant if you care about micro-optimisations. 在大多数实际情况下并不多,但是如果您关心微优化,那仍然很重要。

But you can use an alternative syntax to define an implicit Ordering[T] parameter and invoke methods on the Ordering object directly. 但是,您可以使用其他语法来定义隐式Ordering[T]参数并直接在Ordering对象上调用方法。 Actually even the generated bytecode for the following two methods will be identical (except for the type of the third argument, and potentially the implementation of the respective compare methods): 实际上,即使为以下两种方法生成的字节码也将是相同的(除了第三个参数的类型,以及相应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)
}

In practice the runtime on my machine is the same, when invoking these methods with Int arguments. 实际上,当使用Int参数调用这些方法时,我的机器上的运行时是相同的。

So, if you want to compare types generically in Scala, you should usually use Ordering . 因此,如果要比较Scala中的常规类型,通常应使用Ordering

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

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