麻烦使用scala演员

时间:2011-11-17 06:32:48

标签: scala actor

我已经读过,当使用react时,所有actor都可以在一个线程中执行。我经常并行处理集合,需要输出结果。我不相信System.out.println是线程安全的,所以我需要一些保护。一种方式(传统方式)我可以这样做:

val lock = new Object
def printer(msg: Any) {
  lock.synchronized {
    println(msg)
  }
}

(1 until 1000).par.foreach { i =>
  printer(i)
}

println("done.")

这个第一个解决方案与效率方面的演员相比如何?我不是在创建一个新线程吗?

val printer = actor {
  loop {
    react {
      case msg => println(msg)
    }
  }
}

(1 until 10000).par.foreach { i =>
  printer ! i
}

println("done.")

然而,这似乎不是一个好的选择,因为演员代码永远不会完成。如果我在底部放置一个println,它就永远不会被击中,即使看起来它经历了i的每次迭代。我做错了什么?

4 个答案:

答案 0 :(得分:1)

正如您现在使用的是Actor代码,您只有一个演员正在进行所有打印。正如您在运行代码时所看到的那样,这些值都是由Actor按顺序打印出来的,而在并行收集代码中,它们是乱序的。我不太熟悉并行集合,所以我不知道两者之间的性能提升。

但是,如果您的代码并行执行大量工作,您可能希望使用多个actor。你可以这样做:

def printer = actor {
  loop {
    react {
      case msg => println(msg)
    }
  }
}

val num_workers = 10
val worker_bees = Vector.fill(num_workers)(printer)

(1 until 1000).foreach { i =>
    worker_bees(i % num_workers) ! i
}

def非常重要。这样你实际上就是创造了多个演员,而不只是淹没一个演员。

答案 1 :(得分:1)

要修复你的actor实现,你需要告诉actor在程序退出之前退出。

val printer = actor {
  loop {
    react {
      case "stop" => exit()
      case msg => println(msg)
    }
  }
}

(1 until 1000).par.foreach { printer ! _ }

printer ! "stop"

在两个示例中都有涉及支持parallels库和actor库的线程池,但它们是根据需要创建的。

但是,println是线程安全的,因为它确实锁定了它的内部。

(1 until 1000).par.foreach { println(_) } // is threadsafe

至于表现,有很多因素。第一个是从多个线程争用的锁转移到仅由一个线程(一个actor)使用的锁将提高性能。其次,如果你打算使用演员并想要表演,请使用 阿卡。与scala演员相比,Akka演员的速度非常快。另外,我希望println写入的stdout是一个文件而不是屏幕,因为涉及显示驱动程序会破坏你的性能。

使用parallels库非常适合性能,因此您可以利用多个内核进行计算。如果每个计算都非常小,那么尝试使用actor路由进行集中报告。但是,如果每次计算都很重要并且需要相当多的CPU时间,那么只需使用println本身。你真的没有处于竞争锁定状态。

答案 2 :(得分:1)

一个actor实例永远不会处理多个消息。无论为actor分配什么线程池,每个actor实例当时只占用一个线程,因此可以保证所有打印都将被串行处理。

至于没有完成,演员的执行永远不会从reactloop返回,所以:

val printer = actor {
  loop {
    react {
      case msg => println(msg)
    }
    // This line is never reached because of react
  }
  // This line is never reached because of loop
}

如果您使用loop循环和react替换whilereceive,您会看到while循环内的所有内容都按预期执行。

答案 3 :(得分:0)

我不确定我是否能正确理解你的问题。对我来说,你的演员代码工作正常并终止。

尽管如此,您可以将println保存用于并行集合,因此您真正需要的是这样的:

(1 until 1000).par.foreach { println(_) }

在这里充当魅力。我假设你已经知道输出顺序会有所不同,但我只是想再次强调它,因为这个问题经常出现。所以不要指望数字会以连续的方式向下滚动屏幕。