我有两个数组(我从矩阵中取出(Array [Array [Int]]),我需要从另一个中减去一个。
目前我正在使用这种方法,当我对它进行分析时,它就是瓶颈。
def subRows(a: Array[Int], b: Array[Int], sizeHint: Int): Array[Int] = {
val l: Array[Int] = new Array(sizeHint)
var i = 0
while (i < sizeHint) {
l(i) = a(i) - b(i)
i += 1
}
l
}
我需要这么做数十亿次,所以速度的提高是有利的。
我尝试使用List
代替Array
来收集差异,但速度要快得多,但当我将其转换回Array
时,我将失去所有好处。
我确实修改了下游代码以获取List
以查看是否有帮助,但我需要不按顺序访问列表中的内容,以便再次失去任何收益。
似乎任何一种类型的转换都是昂贵的,我想知道是否有某种方法可以使用更快的地图等。
有更好的方法吗?
不确定我第一次做了什么!?
所以我用来测试它的代码是:
def subRowsArray(a: Array[Int], b: Array[Int], sizeHint: Int): Array[Int] = {
val l: Array[Int] = new Array(sizeHint)
var i = 0
while (i < sizeHint) {
l(i) = a(i) - b(i)
i += 1
}
l
}
def subRowsList(a: Array[Int], b: Array[Int], sizeHint: Int): List[Int] = {
var l: List[Int] = Nil
var i = 0
while (i < sizeHint) {
l = a(i) - b(i) :: l
i += 1
}
l
}
val a = Array.fill(100, 100)(scala.util.Random.nextInt(2))
val loops = 30000 * 10000
def runArray = for (i <- 1 to loops) subRowsArray(a(scala.util.Random.nextInt(100)), a(scala.util.Random.nextInt(100)), 100)
def runList = for (i <- 1 to loops) subRowsList(a(scala.util.Random.nextInt(100)), a(scala.util.Random.nextInt(100)), 100)
def optTimer(f: => Unit) = {
val s = System.currentTimeMillis
f
System.currentTimeMillis - s
}
我认为我第一次这样做的结果恰恰相反......我必须误解或混淆方法。
对于提出一个糟糕的问题我很抱歉。
答案 0 :(得分:6)
使用标准JVM管理单线程的代码是最快的。如果您认为List
更快,那么您要么自欺欺人,要么实际上没有告诉我们您在做什么。将Int
放入List
需要两个对象创建:一个用于创建列表元素,另一个用于设置整数。对象创建所需的时间比数组访问长约10倍。因此,以任何其他方式做到这一点并不是一个成功的主张。
如果你真的,真的需要更快,并且必须保持单个线程,你应该切换到C ++等,并明确使用SSE指令。例如,请参阅this question。
如果你真的,真的需要更快,并且可以使用多个线程,那么最简单的是打包这样的一大块工作(即需要减去的合理数量的矢量对 - 可能至少只要计算机上的处理器数量,就可以将每个块的几百万个元素放入一个列表中,然后调用list.par.map(yourSubtractionRoutineThatActsOnTheChunkOfWork)
。
最后,如果你是破坏性的,
a(i) -= b(i)
当然,内循环中的更快。同样,如果您可以重复使用空格(例如使用System.arraycopy
),那么您最好不要继续分配空间。但是这会改变你所展示的界面。
答案 1 :(得分:1)
您可以使用Scalameter尝试对两个实现进行基准测试,这两个实现至少需要运行JRE 7 update 4和Scala 2.10。我使用了scala 2.10 RC2。
使用scalac -cp scalameter_2.10-0.2.jar RangeBenchmark.scala
进行编译。
使用scala -cp scalameter_2.10-0.2.jar:. RangeBenchmark
运行。
这是我使用的代码:
import org.scalameter.api._
object RangeBenchmark extends PerformanceTest.Microbenchmark {
val limit = 100
val a = new Array[Int](limit)
val b = new Array[Int](limit)
val array: Array[Int] = new Array(limit)
var list: List[Int] = Nil
val ranges = for {
size <- Gen.single("size")(limit)
} yield 0 until size
measure method "subRowsArray" in {
using(ranges) curve("Range") in {
var i = 0
while (i < limit) {
array(i) = a(i) - b(i)
i += 1
}
r => array
}
}
measure method "subRowsList" in {
using(ranges) curve("Range") in {
var i = 0
while (i < limit) {
list = a(i) - b(i) :: list
i += 1
}
r => list
}
}
}
结果如下:
::Benchmark subRowsArray::
Parameters(size -> 100): 8.26E-4
::Benchmark subRowsList::
Parameters(size -> 100): 7.94E-4
您可以得出自己的结论。 :)
堆叠在较大的limit
值上爆炸。我猜这是因为它多次测量性能。