【问题标题】:Scala quickSort 10x slower when using Ordering[T]Scala quickSort 使用 Ordering[T] 时慢 10 倍
【发布时间】:2016-02-10 01:20:34
【问题描述】:

我正在根据自定义排序对整数索引进行排序。我发现这里使用的 Ordering[T] 使排序比使用直接调用 compare 方法的手工快速排序慢至少 10 倍。这似乎成本高得离谱!

val indices: Array[Int] = ...

class OrderingByScore extends Ordering[Int] { ... }

time { (0 to 10000).par.foreach(x => {
  scala.util.Sorting.quickSort[Int](indices.take(nb))(new OrderingByScore)
})}
// Elapsed: 30 seconds

与找到here但修改为添加ord: Ordering[Int]参数的手工排序数组相比:

def sortArray1(array: Array[Int], left: Int, right: Int, ord: Ordering[Int]) = ...

time { (0 to 10000).par.foreach(x => {
  sortArray1(indices.take(nb), 0, nb - 1, new OrderingByScore)
})}
// Elapsed: 19 seconds

最后,同样的代码,但使用了确切的类型 (ord: OrderingByScore):

def sortArray2(array: Array[Int], left: Int, right: Int, ord: OrderingByScore) = ...

time { (0 to 10000).par.foreach(x => {
  sortArray2(indices.take(nb), 0, nb - 1, new OrderingByScore)
})}
// Elapsed: 1.85 seconds

看到每个版本之间的差异如此之大,我感到非常惊讶!

在我的示例中,索引数组是根据在另一个包含组合分数的 Doubles 数组中找到的值进行排序的。此外,排序是稳定的,因为它使用索引本身作为辅助比较。附带说明一下,为了使测试可靠,我必须在并行循环中使用“indices.take(nb)”,因为排序会修改输入数组。与把我带到这里的问题相比,这个惩罚可以忽略不计。关于要点的完整代码here

非常欢迎您提出改进建议。但请尽量不要更改索引和分数数组的基本结构。

注意:我在 scala 2.10 REPL 中运行。

【问题讨论】:

  • 也许是装箱和拆箱成本。

标签: performance scala sorting


【解决方案1】:

问题是scala.math.Ordering 不是专门的。因此,每次使用Int 之类的原语调用比较方法时,Int 类型的两个参数都会被装箱到java.lang.Integer。这会产生很多短寿命的物体,这会大大减慢速度。

spire library 有一个名为spire.algebra.Order 的专门版本的 Ordering,它应该会更快。您可以尝试在您的代码中替换它并再次运行您的基准测试。

尖顶也有sorting algorithms。所以也许就试试这些吧。

基本上,只要您想以高性能方式使用基元进行数学运算,spire 就是您的最佳选择。

此外,如果您想信任结果,请使用适当的微基准测试工具,例如 ThymeJMH 进行基准测试。

【讨论】:

  • API 文档在这里可能会产生误导。 Ordering[T] 定义了 'abstract def compare(x: T, y: T): Int'.. 在我看来,这应该使用直接类型传递而不是装箱。
  • 为了记录,使用 spire 和他们的 Order[Int] 特化导致与我手工制作的快速排序相同的性能。即 1.83 秒
  • @Michel Lemay:关于拳击,问题是Ordering 是通用的,所以所有类型为T 的值都可以在Ordering[T] 中进出 被装箱(就像在 java 中一样)。同样,Sorting.quickSort 是通用的,所以拳击也发生在那里。然而,scala 有一个叫做 specialization 的特性,可以避免这种拳击。因此,如果 both OrderingSorting.quickSort 是专门的,您将不会有任何装箱,这将导致更快的执行。您无法修改标准库以使其专业化,但您可以使用 spire。
  • 感谢您的解释..我只是想弄清楚两者之间的区别。我想这一切都归结为 @sp 注释并具有正确的隐式。
猜你喜欢
  • 1970-01-01
  • 2011-09-16
  • 2021-01-03
  • 2018-01-19
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多