Akka Actors - 锁定单个资源请求

5
我正在使用几个Akka actor来监视我的系统,每个actor负责不同的组件。
其中一些actor操作不应并行执行。因此,我创建了一个持有锁(LockActor)的actor。 一旦actor想要执行这样的操作,他需要向LockActor请求批准,并在获得批准之前不能执行该操作。
如果我想让代码简单化,在请求的actor中,我需要做类似以下的操作:
while (LockActor.isLockHold()) {
    // perform the operation
}

当然,这破坏了整个演员系统的设计......因此,我需要使用一些使代码变得有点复杂的消息:
  1. 演员B需要向锁定演员发送LockRequestMessage
  2. 锁定演员持有一个队列,其中包含锁请求
  3. 如果锁是可能的,则锁定演员将LockApprovalMessage发送给队列中的第一个演员
  4. 当演员B收到LockApprovalMessage(不一定是立即)时,他需要执行发送LockRequestMessage时所需的特定操作(每个演员可以有多个需要锁定的操作)
因此,我的问题是 - 在不破坏演员系统设计的情况下,最好的实现方式是什么,同时尽可能保持代码简单?
3个回答

6

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


1
我没有一个单独的演员来获取锁,而是有几个演员负责不同的组件,每个演员都可以请求锁。此外,LockActor并不仅仅持有锁,还持有所有共享资源。我不确定我理解你的建议 - 你是否建议为每个需要锁定操作添加新的演员来执行操作? - user1768906
2
@tzofia drexin提议,不要询问锁定状态,而是向该锁定发行者角色发送一个命令,例如doTheWorkForMe。如果该角色持有大量锁,则可以在内部将工作委派给其他工作人员角色。 - om-nom-nom
1
谢谢@om-nom-nom。但是这样做会使代码变得复杂,因为本来可以在一个方法中完成的操作(就像我在问题描述中所说的:while(LockActor.isLockHold()) {// perform the operation})现在被分散了。 也许还有其他正确而优雅的解决方案? - user1768906
2
@tzofia Drexin的回答是标准的。一旦你习惯了这种方法,代码就不会更复杂。也许,它甚至会看起来更简单,因为你将避免所有经典的锁问题(死锁、活锁等),同时仍然确保操作是按顺序完成的。 - paradigmatic

4
这里有两个解决方案。
首先,您可以使用询问模式
class MyActor extends Actor {

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

}

请注意,ask方法将创建另一个actor,该actor接收请求消息并完成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
        }
    }


}

你完全可以在同一接收函数中处理这两条消息,但是必须在某个时刻记录演员所处的状态。而become-unbecome机制可以为您完成这种清晰的分离。
请注意,如果您正在使用锁来防止演员对某些共享资源进行变异,则Akka提供了一些更复杂的机制:
- 代理 - http://doc.akka.io/docs/akka/2.1.0-RC2/scala/agents.html - 事务处理器 - http://doc.akka.io/docs/akka/2.1.0-RC2/scala/transactors.html 请查看文档 - 它可能会显著简化您的实现。

1
谢谢您向我介绍了 Akka 的新能力!这正是我正在寻找的——保持 Akka 系统设计和优雅代码并存。 - user1768906

0

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

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

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

  • 每当actor想要使用lock hold进行某些操作时,它会向表示该lock的ActorExecutor发送一个闭包。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接