在阅读了Scala中的演员使用react
之后,我认为react
会共享同一个帖子,因为没有多个react
未决。情况似乎并非如此。
import scala.actors.Actor
import scala.actors.Actor._
class SleepyReactor extends Actor {
def act() {
loop {
react {
case x => {
println("reacting to %s on thread %s".format(x, Thread.currentThread.getName))
Thread.sleep(1000)
println("done with " + x)
}
}
}
}
}
val sleepyOne = new SleepyReactor
sleepyOne.start
sleepyOne ! "first" // runs on thread-5
// wait until completion
sleepyOne ! "second" // runs on thread-3
有人可以解释为什么这些react
在不同的线程上运行,以及何时为react
的角色创建新线程?
我在某处读到react
是基于事件的,我认为这意味着“反应角色”共享一个线程,如果一个人“反应”,其他“反应角色”将排队等到第一个完成。我现在认为我错了。这是如何工作的,它与收到的有何不同?
答案 0 :(得分:9)
对于纯粹的基于事件的actor,它的反应代码与消息发送代码在同一个线程上运行。
但是在Scala中,因为当一个actor在其反应代码中调用阻塞操作并统一基于事件和基于线程的actor(能够组合它们)时,阻止一个线程是不可取的,所以这两种类型的actor都使用相同的线程池但基于线程的actor获取自己的线程,而基于事件的actor根据任务队列共享线程。有关详细信息,请参阅Philipp Haller和Martin Odersky的Actors that Unify Threads and Events
答案 1 :(得分:5)
不要假设每个Actor都有一个单独的线程。 Scala机制创建了一个工作线程池,只有在“阻塞”Actors的大小大于池大小时才会增长该池。当你的演员调用receive
时,它会处于阻塞状态,直到收到消息为止。
答案 2 :(得分:4)
要查看前面答案中描述的效果,您需要生成两个以上的线程。此示例程序生成100个带有receive的线程和100个带有react的线程。
当你运行它时,你可以看到每个接收actor占用一个线程,而反应者共享少量线程。 (在输出排序时最容易看到。)
import scala.actors._
import scala.actors.Actor._
class ReactActor extends Actor {
def act {
loop {
react {
case 'Hello => println("React: " + Thread.currentThread)
}
}
}
}
class ReceiveActor extends Actor {
def act {
while (true) {
receive {
case 'Hello => println("Receive: " + Thread.currentThread)
}
}
}
}
object Main {
def main(args: Array[String]) {
val count = 100
val as = new Array[Actor](2 * count)
for (i <- 0 until count) {
as(i) = new ReactActor
as(count + i) = new ReceiveActor
}
for (a <- as) a.start()
actor {
println(Thread.currentThread)
for (a <- as) a ! 'Hello
}
}
}
典型程序中的排序输出:
Thread[Thread-102,5,main]
React: Thread[Thread-102,5,main]
React: Thread[Thread-102,5,main]
React: Thread[Thread-102,5,main]
...
React: Thread[Thread-102,5,main]
React: Thread[Thread-103,5,main]
React: Thread[Thread-103,5,main]
...
React: Thread[Thread-103,5,main]
React: Thread[Thread-104,5,main]
React: Thread[Thread-104,5,main]
React: Thread[Thread-104,5,main]
...
React: Thread[Thread-104,5,main]
React: Thread[Thread-105,5,main]
React: Thread[Thread-105,5,main]
React: Thread[Thread-105,5,main]
...
React: Thread[Thread-105,5,main]
Receive: Thread[Thread-1,5,main]
Receive: Thread[Thread-10,5,main]
Receive: Thread[Thread-100,5,main]
Receive: Thread[Thread-101,5,main]
Receive: Thread[Thread-11,5,main]
Receive: Thread[Thread-12,5,main]
Receive: Thread[Thread-13,5,main]
Receive: Thread[Thread-14,5,main]
Receive: Thread[Thread-15,5,main]
Receive: Thread[Thread-16,5,main]
Receive: Thread[Thread-17,5,main]
Receive: Thread[Thread-18,5,main]
Receive: Thread[Thread-19,5,main]
Receive: Thread[Thread-2,5,main]
Receive: Thread[Thread-20,5,main]
Receive: Thread[Thread-21,5,main]
...
答案 3 :(得分:3)
调度程序库使用线程池来控制actor的执行。我不知道它使用的逻辑的具体细节,但对我来说,期望它是自然的:
使用池中的多个线程进行初始化,因为多线程应用程序很可能使用多个thead。
以类似队列的方式选择与等待的actor一起使用的线程 - 线程被释放到队列的末尾,并从队列的开头获取。
此外,我假设一些线程用于处理调度本身以及消息传递。