为什么这个数组元素的访问速度比数组视图\ slice快几个数量级?

时间:2017-04-25 21:18:18

标签: scala

我正在编写一个简单的字符串括号余额检查应用程序作为并行编程课程的一部分。 我有两个应用程序顺序部分的实现 - 一个使用索引遍历给定的Array[Char],另一个使用head \ tail方法。

我无法理解为什么我的测试数据(100000000长阵列)的索引访问速度比head \ tail替代方案快几个数量级。

Scalameter报告(测试集中的#elements:100000)

  • 顺序数组::平均执行时间:0.10 ms +无GC
  • head \ tail +(chars.view(idx,until)):平均执行时间:~949.07ms +中等GC量
  • head \ tail +(chars.slice(idx,until)):平均执行时间:603.42ms +中等GC量
  • 列表头\尾(chars.slice(idx,until)):平均执行时间:3.41 ms +中等GC量
  • 列出头部\尾部(chars.view(idx,until)):我在超过45秒(!)+大量GC后终止了测试

我知道view方法应该创建一个集合的惰性视图,而slice方法实际上实现了集合的块 - 这解释了GC调用的差异。但是,我无法理解执行时间的差异。

  • 索引方法和head \ tail方法之间执行时间差异的原因是什么?
  • 为什么head \ tail slice版本的性能优于视图版本?我希望结果是另一种方式。

测试方法的完整代码(对于测试的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)
  }

0 个答案:

没有答案