我正在编写一个简单的字符串括号余额检查应用程序作为并行编程课程的一部分。
我有两个应用程序顺序部分的实现 - 一个使用索引遍历给定的Array[Char]
,另一个使用head \ tail方法。
我无法理解为什么我的测试数据(100000000长阵列)的索引访问速度比head \ tail替代方案快几个数量级。
Scalameter报告(测试集中的#elements:100000)
我知道view方法应该创建一个集合的惰性视图,而slice方法实际上实现了集合的块 - 这解释了GC调用的差异。但是,我无法理解执行时间的差异。
测试方法的完整代码(对于测试的List版本,集合在测量时间之外转换为列表):
def parBalance(chars: Array[Char], threshold: Int): Boolean = {
def traverse(idx: Int, until: Int, initialUnmatchedLeft: Int, initialUnmatchedRight: Int): (Int, Int) = {
def traverseChunkSeq(chars: Seq[Char], unmatchedLeft: Int, unmatchedRight: Int): (Int, Int) =
if (chars.isEmpty) (unmatchedLeft, unmatchedRight)
else chars.head match {
case '(' => traverseChunkSeq(chars.tail, unmatchedLeft + 1, unmatchedRight)
case ')' =>
if (unmatchedLeft > 0) traverseChunkSeq(chars.tail, unmatchedLeft - 1, unmatchedRight)
else traverseChunkSeq(chars.tail, unmatchedLeft, unmatchedRight + 1)
case _ => traverseChunkSeq(chars.tail, unmatchedLeft, unmatchedRight)
}
def traverseChunk(i: Int, unmatchedLeft: Int, unmatchedRight: Int): (Int, Int) =
if (i < until) (unmatchedLeft, unmatchedRight)
else chars(i) match {
case '(' => traverseChunk(i + 1, unmatchedLeft + 1, unmatchedRight)
case ')' =>
if (unmatchedLeft > 0) traverseChunk(i + 1, unmatchedLeft - 1, unmatchedRight)
else traverseChunk(i + 1, unmatchedLeft, unmatchedRight + 1)
case _ => traverseChunk(i + 1, unmatchedLeft, unmatchedRight)
}
// traverseChunk(idx, initialUnmatchedLeft, initialUnmatchedRight)
traverseChunkSeq(chars.view(idx, until), initialUnmatchedLeft, initialUnmatchedRight)
// traverseChunkSeq(chars.slice(idx, until), initialUnmatchedLeft, initialUnmatchedRight)
}
def reduce(from: Int, until: Int): (Int, Int) = {
if (until - from <= threshold) traverse(from, until, 0, 0)
else {
val medium = (until + from) / 2
val ((lo, lc), (ro, rc)) = parallel(reduce(from, medium), reduce(medium, until))
(math.max(0, lo - rc) + ro, lc + math.max(0, rc - lo))
}
}
reduce(0, chars.length) == (0, 0)
}