scala中的阻塞未来?

时间:2012-08-18 15:33:44

标签: scala concurrency actor future

我有一个很长的字符串序列,它们需要由一些处理函数处理,然后作为另一个序列对象收集。这个问题似乎非常适合fork / join类型的攻击。<​​/ p>

该函数是一个实例化成本非常高的类的成员。但是,在期货中实例化和共享单个类对象似乎会导致问题,因此我将实例化处理器数量的4倍实例化,然后将其分解为期货。

// instantiate processing class objects
val processors = 1 to SomeNumber map (x=> new MyProcessor)
val processorstream = Stream.continually(processors).flatten
// the input strings
val input: Seq[String] = some sequence of strings
val splitinput = input.grouped(some large number).toStream
// create futures
val mytask = splitinput.zip(processorstream).collect {
    case (subseq of strings, processor) => future {
        map elements of subsequence of strings with processor}}

然后我像这样收集输出

val result = mytask.map(x => x.apply()).reduce(_++_) // or some appropriate concatenation operator

我的问题是,即使我有8个核心,这也不能给我全部cpu利用率。它只使用一个核心。

为了调查,我尝试的替代方案是

val input: Seq[String] = some sequence of strings
// no stage where I split the input into subsequences
val mytask = input.zip(processorstream).collect {
    case (string, processor) => future {
        process string with processor}}
val result = mytask.map(x => x.apply())

这种替代方案既有效又无效。它实现了完全的cpu利用率,但抛出了几个例外,因为(一个假设)处理器运行的每个字符串太快,有时同一个处理器对象会同时应用于不同的字符串。

我更确定我的假设是处理器工作得太快,因为如果我提供更长的输入(比如说全文文档而不是10个字标题),我会获得完整的cpu利用率,而不会抛出任何异常。

我也试过尝试akka期货和scalaz承诺,当我将输入序列分成子序列时,他们似乎只使用一个cpu。

那么在使用字符串的子序列作为输入时,如何在此实例中使用期货获得完整的cpu利用率?

2 个答案:

答案 0 :(得分:2)

Per @ om-nom-nom:

input.par.map { s => task(s) }

答案 1 :(得分:0)

您可以尝试将ThreadLocal用于可变处理器。相当无用的例子:

val words = io.Source.fromFile("/usr/share/dict/words").getLines.toIndexedSeq

class Processor {
  val sb = new StringBuffer() // mutable!
  println("---created processor---")
  def map(s: String): Int = {
    sb.setLength(0)
    for (i <- 1 to s.length()) {
      sb.append(s.substring(0, i))
    }
    sb.toString().sum.toInt  // don't make any sense out of this
  }
}

val tl = new ThreadLocal[Processor] {
  override protected def initialValue() = new Processor
}

val parRes = words.par.map(w => tl.get.map(w)).sum
val serRes = words.map(    w => tl.get.map(w)).sum
assert(parRes == serRes)

这将默认创建与CPU核心一样多的线程,因为---created processor---消息证明了这一点。