Parallel Aggregate不在列表上工作.length> 8

时间:2016-10-18 16:37:44

标签: scala scala-collections

我正在编写一个小型练习应用,用于计算seq strings中唯一字母(包括Unicode)的数量,我正在使用aggregate作为我尝试并行运行

这是我的代码:

class Frequency(seq: Seq[String]) {
  type FreqMap = Map[Char, Int]

  def calculate() = {
    val freqMap: FreqMap = Map[Char, Int]()
    val pattern = "(\\p{L}+)".r
    val seqop: (FreqMap, String) => FreqMap = (fm, s) => {
      s.toLowerCase().foldLeft(freqMap){(fm, c) =>
        c match {
          case pattern(char) => fm.get(char) match {
            case None => fm+((char, 1))
            case Some(i) => fm.updated(char, i+1)
          }
          case _ => fm
        }
      }
    }

    val reduce: (FreqMap, FreqMap) => FreqMap =
      (m1, m2) => {
        m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, 0)) }
      }

    seq.par.aggregate(freqMap)(seqop, reduce)

  }
}

然后是使用该

的代码
object Frequency extends App {

  val text = List("abc", "abc", "abc", "abc", "abc", "abc", "abc", "abc", "abc");

  def frequency(seq: Seq[String]):Map[Char, Int] = {
    new Frequency(seq).calculate()
  }

  Console println frequency(seq=text)
}

虽然我提供了9次“abc”,结果是Map(a -> 8, b -> 8, c -> 8),因为它适用于任意数量的"abc"> 8

我看过this,好像我正在使用聚合

有什么建议让它发挥作用吗?

1 个答案:

答案 0 :(得分:2)

您正在丢弃已经收集的结果(第一个fm)在您的seqop中。您需要将这些添加到您正在计算的新结果中,例如像这样:

def calculate() = {
    val freqMap: FreqMap = Map[Char, Int]()
    val pattern = "(\\p{L}+)".r
    val reduce: (FreqMap, FreqMap) => FreqMap =
      (m1, m2) => {
        m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, 0)) }
      }
    val seqop: (FreqMap, String) => FreqMap = (fm, s) => {
      val res = s.toLowerCase().foldLeft(freqMap){(fm, c) =>
        c match {
          case pattern(char) => fm.get(char) match {
            case None => fm+((char, 1))
            case Some(i) => fm.updated(char, i+1)
          }
          case _ => fm
        }
      }

      // I'm reusing your existing combinator function here:
      reduce(res,fm)
    }

    seq.par.aggregate(freqMap)(seqop, reduce)
}

根据并行集合如何划分工作,您可以丢弃其中的一部分。在你的情况下(9x“abc”),它将事物划分为8个并行的seqop操作,这意味着你只丢弃一个结果集。这取决于数字,如果你运行说17x“abc”它运行在13个并行操作中,丢弃4个结果集(在我的机器上无论如何 - 我不熟悉底层代码以及它如何划分工作,这可能取决于使用的ExecutionContext / Threadpool以及随后的CPU /核心数等等)。

通常并行集合是顺序集合的替代品,这意味着如果删除.par,您仍应获得相同的结果,尽管通常较慢。如果使用原始代码执行此操作,则会得到1的结果,这会告诉您它不是并行化问题。这是一种很好的方法,可以测试你在使用它们时是否正确。

最后但并非最不重要:因为你使用相同的变量名两次,然后是影子fm,这对我来说比平常更难发现。不这样做会使代码更具可读性,并且更容易发现错误。