我有一个可以分发的密集型任务,但其最终结果需要累积并传递给另一个方法。
具体来说,假设我正在对大量文本文件中的单个文件进行单词计数。
到目前为止,我所制定的版本看起来像这样:
import scala.actors.Actor
import scala.actors.Actor._
import scala.collection.mutable.{ArrayBuffer => mArray}
case object Stop
class Collector(val bin: mArray[(String, Int)], tcount: Int) extends Actor {
def act() {
loop {
receive {
case (fn: String, val: Int) => {
// the following "bin" object is what I ultimately need to get back
bin.append((fn, val))
}
case Stop => {
tcount -= 1
if(tcount == 0) exit()
}}}}}
class Processor(col: Collector, flist: Seq[File]) extends Actor {
def act() {
for(fn <- flist) {
val wcount = count words in fn // just a place holder for word counting code
col ! (fn, wcount)
}
col ! (id, Stop)
}
}
我可以想到几个自制方法使主方法等待收集器完成然后处理“bin”对象。
但是上面检索“bin”并将其交回main或者你有什么的正确scala方法是什么?
答案 0 :(得分:0)
对于一个actor,你不会“检索”任何东西,因为调用actor方法可能很危险。
相反,你让演员发出答案。您可以为GET
对象添加案例,或者您可以让它在bin
的处理程序中的某处发送Stop
。
答案 1 :(得分:0)
您可以使用方法!!
ping一个actor以创建将来的结果。接收消息的参与者可以使用reply
填写结果。
但是,您通过使用执行程序来节省大量管理工作,这对于并行化任务更好(您在这里没有真正的并发情况会特别有用)。
以下是基于Scala 2.10(即将发布,您现在可以使用2.10.0-M6),因为它包含改进的并发框架:
import java.io.File
import concurrent._
import java.util.concurrent.Executors
// count words in a file - probably not the best possible way to write this
def wc(f: File): Int = io.Source.fromFile(f).getLines.map(
_.split(' ').filterNot(_ == "").size).sum
// utility method to get files within a directory (non-recursive!)
def filesInDir(dir: File): Seq[File] = dir.listFiles.toSeq.filter(_.isFile)
// process method which takes a list of files, spawns a word-count for each
// and collects the individual future results into a `Map` whose future is returned
def process(files: Seq[File])(implicit exec: ExecutionContext)
: Future[Seq[(File, Either[Throwable, Int])]] = {
val futs = files.map { f =>
// `future` submits the body for asynchronous processing. In order to
// gracefully handle IO errors, a successful result is wrapped in `Right`,
// and an exception in `Left`. The caller can decide how to handle errors.
future {
f -> (try {
Right(wc(f))
} catch {
case e: Throwable => Left(e)
})
}
}
// collect all the individual results into one result object.
// the new single `Future` is only complete after all of the individual futures
// have completed.
Future.sequence(futs)
}
示例:
// use as many threads as there are processor cores
val poolSize = sys.runtime.availableProcessors()
// create a new executor context to be used for spawning
implicit val exec = ExecutionContext.fromExecutor(
Executors.newFixedThreadPool(poolSize))
// call the process
val map = process(filesInDir(new File("/my/directory")))
// execute some body when the future is completed
map.onSuccess { case m =>
m foreach println
}