只是在这里:
编辑
答案是“是” - 如果您的演员没有阻止您的代码中的任何内容并且您正在使用 react ,那么你可以运行你的 “同时” 单个线程内的程序(尝试设置系统属性 actors.maxPoolSize 找出来)。
react
actors.maxPoolSize
其中一个更明显的原因是 丢弃调用堆栈所必需的 不然的是 loop 方法将以a结尾 StackOverflowError 。事实上,框架相当巧妙地结束了 react 投掷一个 SuspendActorException ,它由循环代码捕获,然后运行 react 再次通过 andThen 方法。
loop
StackOverflowError
SuspendActorException
andThen
看看吧 的 mkBody 强> 方法 Actor 然后是 的 seq 强> 查看循环如何重新安排自己的方法 - 非常聪明的东西!
mkBody
Actor
seq
那些“丢弃堆栈”的陈述让我感到困惑了一段时间,我想我现在得到它,这是我现在的理解。在“接收”的情况下,在消息上有一个专用的线程阻塞(在监视器上使用object.wait()),这意味着完整的线程堆栈可用并准备好从接收到“等待”的点继续信息。 例如,如果您有以下代码
def a = 10; while (! done) { receive { case msg => println("MESSAGE RECEIVED: " + msg) } println("after receive and printing a " + a) }
线程将在接收呼叫中等待,直到收到消息,然后继续打开并在线程被阻止之前打印“接收并打印10”消息并且值为“10”。
如果没有这样的专用线程,则反应方法的整个方法体被捕获为闭包,并由接收消息的相应actor上的某个任意线程执行。这意味着只有那些可以作为闭包单独捕获的语句才会被执行,并且这就是“Nothing”的返回类型所在的位置。请考虑以下代码
def a = 10; while (! done) { react { case msg => println("MESSAGE RECEIVED: " + msg) } println("after react and printing a " + a) }
如果react有返回类型的void,则意味着在“react”调用之后有语句是合法的(在示例中println语句打印消息“在反应并打印10”之后),但实际上永远不会被执行,因为只有“反应”方法的主体被捕获并排序以便稍后执行(在消息到达时)。由于react的契约具有返回类型“Nothing”,因此不能有任何语句响应,并且没有理由维持堆栈。在上面的示例中,变量“a”不必保持为在根本不执行react调用之后的语句。请注意,反应主体所需的所有变量已经被捕获为闭包,因此它可以执行得很好。
java actor框架 基里姆 实际上通过保存堆栈来进行堆栈维护,该堆栈在反应中获得消息。
首先,每个演员都在等待 receive 占据了一个线索。如果它从未收到任何东西,该线程将永远不会做任何事情。一个演员 react 在收到某些东西之前不会占用任何线程。一旦收到某个东西,就会为它分配一个线程,并在其中初始化。
receive
现在,初始化部分很重要。接收线程应该返回一些东西,一个反应线程不会。所以前一个堆栈状态在最后一个末尾 react 可以,并且完全被丢弃。无需保存或恢复堆栈状态使线程更快启动。
您可能需要其中一个或多个的各种性能原因。如您所知,Java中包含太多线程并不是一个好主意。另一方面,因为你必须先将一个actor附加到一个线程 react ,它更快 receive 一条消息而不是 react 它。因此,如果你有演员收到许多消息,但对它做的很少,额外的延迟 react 可能会让你的目的太慢。
我没有对scala / akka做过任何重大工作,但我知道演员的安排方式存在很大差异。 Akka只是一个聪明的线程池,是时间切片演员的执行... 每个时间片都是一个消息执行完成的演员不像Erlang那样可能是每个指令?!
这使我认为反应更好,因为它暗示当前线程考虑其他参与者进行调度,其中接收“可能”参与当前线程以继续为同一个actor执行其他消息。