【问题标题】:Akka Actors - Lock single resource requestAkka Actors - 锁定单个资源请求
【发布时间】:2012-11-13 18:48:00
【问题描述】:

我正在使用多个 akka Actor 来监控我的系统,每个参与者负责不同的组件。

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

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

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

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

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

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

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

【问题讨论】:

    标签: java scala akka actor


    【解决方案1】:

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

    【讨论】:

    • 我没有一个单独的actor来获取锁,但是有几个actor负责不同的组件并且每个actor都可以请求锁。此外,LockActor 并不是真的只持有锁,而是持有所有共享资源。我不确定我是否理解您的建议 - 您是否建议我为每个需要锁定操作添加执行该操作的新演员?
    • @tzofia drexin 建议不要要求锁发送命令,例如doTheWorkForMe 到那个锁发行者演员。如果那个演员持有很多锁,它可以在内部将工作委托给其他工人演员。
    • 谢谢@om-nom-nom。但是通过这种方式,代码保持复杂,因为可能在一种方法中的操作(正如我在问题中描述的那样:while(LockActor.isLockHold()) {// perform the operation})现在分散了。也许还有其他正确的和优雅的解决方案?
    • @tzofia Drexin 答案是标准。一旦您习惯了这种方法,代码就不会更复杂。也许,它对您来说甚至看起来更简单,因为您将避免所有经典的锁问题(死锁、活锁等),同时仍然确保操作是按顺序完成的。
    【解决方案2】:

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

    首先,您可以使用ask pattern

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

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

    如果您不想使用询问模式,您可以很好地使用become-unbecome mechanism,如下所示:

    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 为此提供了一些更复杂的机制:

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

    【讨论】:

    • 感谢您向我介绍了 Akka 的新功能!这正是我一直在寻找的——保持 akka 系统设计和优雅的代码。
    【解决方案3】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2015-01-18
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 1970-01-01
      • 2018-07-22
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      相关资源
      最近更新 更多