5

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

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

如果我想让代码简单,在请求的演员中,我需要做类似的事情:

while (LockActor.isLockHold()) {
    // perform the operation
}

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

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

  1. Actor B 需要向 LockActor 发送 LockRequestMessage
  2. LockActor 持有持有锁请求的队列
  3. 如果锁定是可能的,LockActor 将 LockApprovalMessage 发送到队列中的第一个 Actor
  4. 当参与者 B 收到 LockApprovalMessage(不一定立即)时,他需要执行发送 LockRequestMessage 时所需的特定操作(每个参与者可以有多个需要锁定的操作)

所以我的问题是 - 在不破坏演员系统设计但仍保持代码尽可能简单的情况下实现此类事情的最佳方法是什么?

4

3 回答 3

6

与其使用单个actor来获取锁,为什么不使用单个actor来完成工作呢?这是actor模型中的首选方式。

于 2012-11-26T09:59:03.883 回答
4

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

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

class MyActor extends Actor {

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

}

请注意,ask 方法将创建另一个接收请求消息并完成未来的参与者 - 请参阅文档以获取更多详细信息。

如果您不想使用 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
        }
    }


}

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

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

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

于 2012-11-26T12:54:21.000 回答
0

这是想法,我不知道细节,因为我是scala的新手:

  • 创建自定义类 ActorExecutor,它是一个类型化的 Actor,它接受闭包作为消息,并通过调用该闭包来处理该消息。

  • 为每个锁创建一个 ActorExecutor 的实例

  • 每当一个actor想要在锁保持的情况下进行一些操作时,它都会向代表该锁的ActorExecutor发送一个闭包。

这样,发送到具体 ActorExecutor 实例的所有操作都按顺序执行。

于 2012-11-26T11:53:21.680 回答