【问题标题】:Erlang/OTP How to notify parent process that child processes are idle and no messages in their mailboxErlang/OTP 如何通知父进程子进程处于空闲状态且邮箱中没有消息
【发布时间】:2015-02-19 00:00:22
【问题描述】:

我想设计一个进程层次结构,其中有一个父进程 P,它充当看门人并将工作(来自其客户端进程的消息/事件)委托给它的子进程 C1、C2..Cn,它们与每个进程协作其他并可能将结果发送回 P。子进程不能与外部的任何进程通信,只能与 P 通信。

挑战在于,尽管 P 可能有来自其客户端的多条消息,但它应该只接受一条消息,将工作委托给 C1..Cn 并且只接受来自其客户端的下一条消息

  • 当它的所有子进程都完成(或空闲)并且没有更多消息在 C1 到 Cn 之间循环时。
  • P 完成接受来自 C1..Cn 的消息,以便将结果返回给其客户端

约束:

  • 对我来说空闲是当他们等待接收(阻塞)或只是退出时。
  • C1 到 Cn 是有限状态机。它们中的一些或全部可能会将消息发送回 C。或者可能没有消息要发送回 C。即使没有消息发送回 C,C 也必须确定所有这些都已完成,并且之间没有消息他们。
  • 如果 C1 到 Cn 中的任何一个被抢占,则认为它很忙(这可能很明显,但我想我会把它放在这里完成)并且 C 不会收到下一条消息

是否有一个 OTP 模式或库可以为我做到这一点(在我破解某些东西之前?)。我知道process_info 可以让我知道进程的邮箱是否为空,我可以继续从 P 检查孩子的邮箱,但从 P 轮询是不必要的。

一般编辑:我正在尝试在 Erlang 平台上实现 Flow Based Programming 的反应变体。这具有“分层流程”或组合的概念,它们本身可能包含组合流程,直到我们到达一些实际代码框...我要去研究(查看监视器、process_info、process_flag)但我想回应你的优秀答案

编辑递归父进程:C1 和 Cn 中的每一个本身都可以是父进程/复合进程。如果我只是产生进程并让它们立即退出,我将不得不每次都创建复合材料链,因为 C1..Cn 本身可能是复合材料(产生复合材料......等等)。最后,当我们到达叶盒(不是复合节点)时,它们应该是有限状态机。所以如果它们是 FSM,我不确定生成并让它们快速退出。

编辑 TKOWAL:由于我正在尝试创建通用父/复合进程,它不知道任务“何时”结束。它所做的只是将它从其子代接收到的消息转发给它的兄弟姐妹,并带有“约束”,即在其子代“完成”之前它不会接受来自其客户端/兄弟姐妹的下一条消息。孩子 C1..Cn 可能不仅发送一条消息,而且发送许多消息。我从您的提议中了解到,wait_for_task_finish 将在收到第一条消息时停止阻塞。但是 P 的孩子也可能发出更多的消息。 P 应该等待所有消息。此外,具有 task_end 符号将因相同的原因不起作用(即,孩子可能会收到多条消息)

【问题讨论】:

    标签: erlang erlang-otp


    【解决方案1】:

    我不认为,有现成的库,但它真的很容易破解,除非我错过了什么。您的 P 流程应该如下所示:

    ready_for_next_task() ->
        receive
            {task, Task, CallerPid} ->
                send_task_to_workers(Task)
        end,
        wait_for_task_finish(CallerPid).
    
    wait_for_task_finish(CallerPid) ->
        receive
            {task_end, Response} ->
                CallerPid ! Response
        end,
        ready_for_next_task().
    

    wait_for_task_finish/1 你只有一个接收子句,所以它不会接受下一个任务,直到当前任务完成。如果您正在等待工作人员的多个响应,您只需将第二个子句添加到 receive 并带有部分响应并递归调用 wait_for_task_finish/1

    最好有一些指示处理结束,因为您无法保证消息传递时间。这意味着,您可以检查当前所有进程是否都在等待消息并认为它们已结束处理,但实际上,它们尚未启动,或者其中一个向另一个发送消息,而您在第二个收到消息之前捕获了它们在消息框中。

    如果进程C1..Cn只有部分实际工作,不知道进度,那么看门人P应该知道有多少部分,一一接收,然后调用ready_for_next_task/1 .

    【讨论】:

    • 我过度简化了我的问题,造成了混乱。请参阅 EDIT GENERAL 和 EDIT TKOWAL
    【解决方案2】:

    鉴于启动 Erlang 进程的成本非常低,您的看门人可以为每个传入任务启动新的子进程,然后等待它们完成工作后全部正常退出。

    但总的来说,听起来您正在寻找一个进程池。其中一些已经可用,例如poolboysidejob。池可以是harder to get right than you think,因此我建议在尝试编写自己的之前使用现有的经过验证的池实现。

    【讨论】:

    • 我过度简化了我的问题,造成了混乱。请参阅 EDIT GENERAL 和 EDIT RECURSIVE PARENTS
    【解决方案3】:

    经过编辑,这变成了完全不同的问题,所以我发布了新的答案。

    如果您正在尝试编写基于流的编程,那么您可能正在解决错误的问题。 FBP 是有效的,因为几乎所有内容都是异步的,您在完成上一个请求后立即开始处理下一个请求。

    所以,答案是——不要等孩子完成:

    在 FBP 中,组件之间没有时间依赖关系。所以如果我 有一大块数据,它应该能够从一端流出 图表到另一个,无论任何其他数据如何 被处理。为了对 FBP 系统进行编程,您必须最小化 你的依赖。

    source

    在创建父子块时,您知道块之间的所有连接,因此只需配置子块将处理后的数据直接发送到下一个块。例如:P1 有孩子 C1 和 C2。您向 P1 发送消息,它会将其委托给 C1,数据包在 C1 和 C2 之间流动几次,然后,C1 或 C2 将其直接发送给 P2。

    块应该是无状态的。它们的输出不应依赖于先前的请求,因此即使 C1 和 C2 正在处理来自 P1 的两个不同请求的数据 - 也可以。在某些情况下,P1 获取数据包 D1 然后是 D2,但会以不同的顺序输出答案 R2 然后是 R1。也可以。您可以使用 Erlang reference 标记消息,然后检查哪个响应来自哪个请求。

    【讨论】:

      猜你喜欢
      • 2012-08-12
      • 2011-03-17
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      • 2014-10-08
      • 2014-06-07
      • 2012-04-27
      • 2023-03-31
      相关资源
      最近更新 更多