Akka Actors - 锁定单一资源请求

5 java scala actor akka

我正在使用几个akka演员来监控我的系统,每个演员负责一个不同的组件.

一些演员操作不应该并行执行.所以我创建了一个持有锁(LockActor)的actor.一旦演员想要执行此类操作,他需要向LockActor请求批准,并且在获得批准之前他不能执行操作.

如果我想让代码变得简单,那么在请求的actor中我需要做类似的事情:

while (LockActor.isLockHold()) {
    // perform the operation
}
Run Code Online (Sandbox Code Playgroud)

这当然打破了演员系统的整体设计......

所以我需要使用使代码有点复杂的消息:

  1. Actor B需要将LockRequestMessage发送给LockActor
  2. LockActor持有保存锁请求的队列
  3. 如果可以锁定,LockActor会将LockApprovalMessage发送给队列中的第一个actor
  4. 当actor B收到LockApprovalMessage(不一定立即)时,他需要执行发送LockRequestMessage时所需的特定操作(每个actor可以有几个需要锁的操作)

所以我的问题是 - 什么是最好的方式实现这样的事情没有打破演员系统的设计,但仍保持代码尽可能简单?

dre*_*xin 6

而不是使用单个actor获取锁定,为什么不只使用单个actor来完成工作?这是actor模型中的首选方式.

  • @tzofia drexin建议不要求锁发送命令,例如doTheWorkForMe给那个锁发行者演员.如果该actor拥有大量锁,它可以在内部将工作委托给其他工作者. (2认同)
  • @tzofia Drexin答案是标准.一旦习惯了这种方法,代码就不会更复杂.也许,它甚至看起来更简单,因为你将避免所有经典的锁定问题(死锁,活锁等),同时仍然确保操作是按顺序完成的. (2认同)

Mar*_*ila 4

我在这里看到两种解决方案。

首先,您可以使用询问模式

class MyActor extends Actor {

    def receive = {
        case Start: {
            val f = lockActor ? LockRequestMessage
            f onSuccess {
                case LockApprovalMessage => {
                    //todo: do your thing
                }
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,ask 方法将创建另一个参与者,该参与者接收请求消息并完成 future - 有关更多详细信息,请参阅文档。

如果你不想使用ask模式,你可以很好地使用become-unbecome机制,如下所示:

class MyActor extends Actor {
    import context._

    def receive = {
        case Start: {
            lockActor ! LockRequestMessage
            become(waitForApproval)
        }
    }    

    def waitForApproval = {
        case LockApprovalMessage => {
            //todo: do your thing
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

您可以很好地在同一个接收函数中处理这两条消息,但您必须记录参与者在某个时刻所处的状态。“变得不合适”机制会为您完成这种干净的分离。

请注意,如果您使用锁来防止参与者改变某些共享资源,Akka 为此提供了一些更复杂的机制:

查看文档 - 它可能会显着简化您的实施。