如何将数据从子工作进程发送到父进程?

时间:2019-09-07 23:38:27

标签: elixir

我有2个模块,一个是主管,另一个是其工作人员。我已经在第二个(子)模块中计算了一些内容,如何将该值发送到父(主管)模块?

defmodule VampSupervisor do
  use Supervisor

  def start_link(init_arg) do
    Supervisor.start_link(__MODULE__, init_arg)
  end

  def init(init_arg) do
    Process.flag(:trap_exit, true)
    [start,last] = init_arg
    nodes = Enum.chunk_every(start..last, 10)
    children = Enum.map(nodes, fn(chunk_list) ->
      worker(FACT, [chunk_list], [id: List.first(chunk_list), restart: :permanent])
    end)
    supervise(children, strategy: :one_for_one)
  end
end

defmodule FACT do
  use GenServer
  def start_link(init_arg) do
         pid = spawn_link(__MODULE__,:init,[init_arg])
    {:ok,pid}
  end

  def init(init_arg) do
    Enum.each(init_arg, fn(x)->
      spawn(__MODULE__,:main,[x])
    end)
  end

 def main(n) do
    list = make_factor(n,round(:math.sqrt(n)),[])
    {:ok,pid}=GenServer.start_link(VampServer, list)
    Enum.each(list, fn(_)->
      {x,[head,tail]} = GenServer.call(pid,{:check_vampire,n})
      if x==n do
        IO.puts("#{x} #{head} #{tail}") **This has be sent back to supervisor**
      end
    end)
end

2 个答案:

答案 0 :(得分:2)

您的方法有很多问题。

  1. Supervisor.Spec.supervisor/3Supervisor.Spec.worker/3已被弃用,应避免使用;应该使用child specs
  2. Supervisor并非旨在接收用户回调。它仅有的回调是Supervisor.init/1。应该接收用户消息的进程将成为工作进程。
  3. 您滥用GenServer来进行VampServer中的简单函数调用。

代替这个

{:ok, pid} = GenServer.start_link(VampServer, list)
Enum.each(list, fn _ ->
  GenServer.call(pid, {:check_vampire, n})
end)

一个人应该实现一个普通的旧函数Vamp.check_vampire/1,然后像

那样显式调用它
Enum.each(list, fn _ ->
  Vamp.check_vampire(n)
end)

GenServer.call/3是同步的,几乎可以完全执行普通函数的工作。


总结。使用两个工作程序以VampSupervisor的身份启动Supervisor:两个工作人员:FACT将进行计算,而FACTConsumer将在需要时从FACT接收消息。

答案 1 :(得分:0)

您似乎正在使用主管和工人进行一些临时工作,然后再进行报告。

通常,您在应用程序树中启动SupervisorDynamicSupervisor,这些管理者会得到命名,因此您可以通过节点的名称来引用它们。这些主管本来应该是长期存在的,并且可能不适合您的用例。

一个更好的解决方案可能是尝试Task.async/1。 (另请参见Task上的the guides。)这将使您并行触发一堆计算,并使它们重新结合在一起。

或者,您可以定义一个模块来加速在TaskSupervisor下受监管的任务,该模块在创建时将获得带有self()的调用者的pid。但是,在这种情况下,我认为Task.async/1可能是您的最佳选择。