我有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
答案 0 :(得分:2)
您的方法有很多问题。
Supervisor.Spec.supervisor/3
和Supervisor.Spec.worker/3
已被弃用,应避免使用;应该使用child specs。Supervisor
并非旨在接收用户回调。它仅有的回调是Supervisor.init/1
。应该接收用户消息的进程将成为工作进程。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)
您似乎正在使用主管和工人进行一些临时工作,然后再进行报告。
通常,您在应用程序树中启动Supervisor
和DynamicSupervisor
,这些管理者会得到命名,因此您可以通过节点的名称来引用它们。这些主管本来应该是长期存在的,并且可能不适合您的用例。
一个更好的解决方案可能是尝试Task.async/1
。 (另请参见Task
上的the guides。)这将使您并行触发一堆计算,并使它们重新结合在一起。
或者,您可以定义一个模块来加速在TaskSupervisor
下受监管的任务,该模块在创建时将获得带有self()
的调用者的pid。但是,在这种情况下,我认为Task.async/1
可能是您的最佳选择。