Actor 模型可用于将可变状态与外界隔离。当您具有可变状态(例如分配给多个并发进程的 ID 的全局注册表)时,您可以将该可变状态包装在 Actor 内,并使客户端通过消息传递与 Actor 进行通信。这样,只有参与者才能直接访问可变状态,正如您所说,客户端消息会排队等待一一读取和处理。消息的不可变性非常重要。
为了避免队列变满,消息处理(react
, receive
等)尽可能短。长时间运行的任务应该交给其他参与者:
1. Actor A receives a message M from sender S
2. A spawns a new actor C
3. A sends (S, f(M)) to C
4. In parallel:
4a. A starts processing the next message.
4b. C does the long-running or dangerous (IO) task,
When finished, sends the result to S,
and C terminates.
在此过程中的一些替代方案:
- C sends
(S, result)
返回给A,然后转发给S
- A 保留一个映射
ActorRef C => (Sender S, Message M)
所以万一它看到 C 失败 http://doc.akka.io/docs/akka/2.0.3/scala/fault-tolerance.html,它可以用新的 Actor 重试处理 M。
回顾一下,一个 Actor 是多线程的,多个客户端可以从不同的线程向它发送多条消息,并且保证 Actor 将串行处理所有这些消息(尽管顺序可能会受到各种非过度的影响)严格约束)。
请注意,虽然演员的react
code 可以在不同的线程上执行 http://doc.akka.io/docs/akka/2.0.3/scala/dispatchers.html,在单个给定时间点,它仅在单个给定线程上执行(您可以想象 Actor 在调度程序认为合适时从一个线程跳转到另一个线程,但这是一个技术细节)。Note:内部状态仍然不需要同步,因为 Actors保证发生在语义之前 http://doc.akka.io/docs/akka/snapshot/general/jmm.html处理消息之间。
并行性是通过多个 Actor 并行工作来实现的,通常形成主管层级 http://doc.akka.io/docs/akka/2.0.3/general/supervision.html or 平衡工作量 http://doc.akka.io/docs/akka/2.0.3/scala/routing.html.
请注意,如果您需要的只是并发/异步计算,但您没有或可以摆脱全局状态,Futures是更好的作曲 http://doc.akka.io/docs/akka/2.0.3/scala/futures.html和更容易的概念。