【问题标题】:How to know if an actor is idle如何知道演员是否空闲
【发布时间】:2012-07-07 17:52:38
【问题描述】:

我有未知数量的作业要由已知(当然)数量的演员执行。演员完成工作后,初始工作数量可能会增加。也就是说,演员在完成其任务后,可能会添加要执行的新作业。

我处理这个问题的方式是让每个参与者在完成其工作后向主节点发送一条消息,不仅包含执行结果,还包含一个“标志”,表明参与者现在处于空闲状态。主人有一个作业队列和一个空闲演员队列,每当演员发送“作业完成消息”时,主人将检查该演员是否还有其他事情要做......依此类推,直到作业队列是空的,空闲队列已满……那时我关闭了系统。这里没有太多的监督,所以我觉得自己做得不好……

我没有使用路由器,因为我找不到向路由器查询空闲演员的方法,所以我的问题是:

在 Akka 中处理上述情况的“正确”方法是什么?

【问题讨论】:

    标签: java actor akka


    【解决方案1】:

    你应该看看Akka's routing capabilites. SmallestMailboxRouter 可能是你要找的。​​p>

    作为替代方案,您可以按需创建演员,即对于每个任务,都会动态创建一个新演员。中心参与者跟踪当前活动的所有参与者。一旦一个工作actor完成,它会向自己发送一个PoisonPill并通知master它的关闭(主动地,或者通过Akka将发送给监督actor的标准Terminate消息)。一旦没有更多的活动参与者,即没有更多任务,控制参与者就会关闭系统。

    看完评论后补充: 看看SmallestMailboxLike 的来源,SmallestMailboxRouter 混合的 Scala 特征。警告:您应该具备 Scala 的基本知识。但是如果你想用Akka的话,这通常是个好主意……方法isProcessingMessage(ActorRef)可以理解为isNotIdle(ActorRef)

    // Returns true if the actor is currently processing a message.
    // It will always return false for remote actors.
    // Method is exposed to subclasses to be able to implement custom
    // routers based on mailbox and actor internal state.
    protected def isProcessingMessage(a: ActorRef): Boolean = a match {
      case x: LocalActorRef ?
        val cell = x.underlying
        cell.mailbox.isScheduled && cell.currentMessage != null
      case _ ? false
    }
    
    // Returns true if the actor currently has any pending messages
    // in the mailbox, i.e. the mailbox is not empty.
    // It will always return false for remote actors.
    // Method is exposed to subclasses to be able to implement custom
    // routers based on mailbox and actor internal state.
    protected def hasMessages(a: ActorRef): Boolean = a match {
      case x: LocalActorRef ? x.underlying.mailbox.hasMessages
      case _                ? false
    }
    

    【讨论】:

    • 我通过了 Akka 的路由,这就是为什么我决定不使用路由器(也许我应该自己编写),因为我无法查询路由器关于工人的空闲状态(也许我错了,可以你给我指出在哪里看?)
    • 不是按回车的意思...反正我会研究毒丸解决方案,就像我现在正在做的那样,我不杀工人我只是将其设置为空闲以便它可以被重新利用......当我没有更多的任务并且所有的工作人员都空闲而不是我知道我已经完成了。
    • 所以我会写我自己的路由器:)
    【解决方案2】:

    另一种策略是使用 BalancingDispatcher 和 RoundRobinRouter(作为演员“池”)。来自 Akka 文档:

    BalancingDispatcher
    # This is an executor based event driven dispatcher that will try to redistribute work from busy actors to idle actors.
    
    
    
    
    # All the actors share a single Mailbox that they get their messages from.
    
    It is assumed that all actors using the same instance of this dispatcher can process all messages that have been sent to one of the actors; i.e. the actors belong to a pool of actors, and to the client there is no guarantee about which actor instance actually processes a given message.
    
    # Sharability: Actors of the same type only
    
    # Mailboxes: Any, creates one for all Actors
    
    # Use cases: Work-sharing
    

    在 application.conf 中定义您的调度程序或在启动时以编程方式加载它。

    private final static Config akkaConfig = ConfigFactory.parseString(
    
                "my-dispatcher.type = BalancingDispatcher \n" +
                "my-dispatcher.executor = fork-join-executor \n" +
                "my-dispatcher.fork-join-executor.parallelism-min = 8 \n" +
                "my-dispatcher.fork-join-executor.parallelism-factor = 3.0 \n" +
                "my-dispatcher.fork-join-executor.parallelism-max = 64 "
    );
    

    然后为路由定义路由器和调度程序。

    getContext().actorOf(new Props(MyActor.class).withRouter(new RoundRobinRouter(10)).withDispatcher("my-dispatcher"), "myActor");
    

    因此路由器将简单地继续“分发”消息,而调度程序将运行选定的参与者(并且它也实现工作窃取)

    【讨论】:

      【解决方案3】:

      Balancing Dispatcher 将只为所有使用 BalancingDispatcher 创建的所有创建的 Actor 使用一个邮箱。所以它会让你的工作变得简单。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-25
        • 1970-01-01
        • 1970-01-01
        • 2012-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多