我正在根据自定义订购对整数索引进行一些排序。我发现这里使用的Ordering [T]使用直接调用compare方法比使用手工制作的quickSort慢至少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
与手工制作的sortArray相比,找到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
我很惊讶地看到每个版本之间存在这样的差异!
在我的示例中,indices数组根据在包含组合分数的另一个Doubles数组中找到的值进行排序。此外,排序是稳定的,因为它使用索引本身作为次要比较。另一方面,为了使测试可靠,我必须" indices.take(nb)"在并行循环中,因为排序修改输入数组。与我带来的问题相比,这种惩罚可以忽略不计。要点here上的完整代码。
您的建议值得欢迎改进..但尽量不要改变索引和分数数组的基本结构。
注意:我在scala 2.10 REPL中运行。
答案 0 :(得分:5)
问题是scala.math.Ordering
不是专门的。因此,每次使用类似Int
的原语调用compare方法时,Int
类型的两个参数都被加框为java.lang.Integer
。这就产生了很多短命的物体,这大大减慢了事情。
spire library有一个名为spire.algebra.Order的Ordering的专用版本应该更快。您可以尝试在代码中替换它并再次运行基准测试。
尖顶也有sorting algorithms。所以也许只是试试那些。
基本上,无论何时你想以高性能的方式对基元进行数学运算,尖顶都是可行的方法。