我已经读过,当使用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
的每次迭代。我做错了什么?
答案 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实例当时只占用一个线程,因此可以保证所有打印都将被串行处理。
至于没有完成,演员的执行永远不会从react
或loop
返回,所以:
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
替换while
和receive
,您会看到while循环内的所有内容都按预期执行。
答案 3 :(得分:0)
我不确定我是否能正确理解你的问题。对我来说,你的演员代码工作正常并终止。
尽管如此,您可以将println
保存用于并行集合,因此您真正需要的是这样的:
(1 until 1000).par.foreach { println(_) }
在这里充当魅力。我假设你已经知道输出顺序会有所不同,但我只是想再次强调它,因为这个问题经常出现。所以不要指望数字会以连续的方式向下滚动屏幕。