Elixir 长生不老药:在主管内部获取流程pid
我有两种由主管启动的流程:一些工人和一个工人需要向其报告的控制器。为此,他们需要知道控制器的pid 我曾考虑过两种方法,但都不管用 立即开始 其原理是一次启动所有过程,然后检索控制器的pid,然后将其发送给所有工人,以便他们可以开始工作。代码如下所示:Elixir 长生不老药:在主管内部获取流程pid,elixir,Elixir,我有两种由主管启动的流程:一些工人和一个工人需要向其报告的控制器。为此,他们需要知道控制器的pid 我曾考虑过两种方法,但都不管用 立即开始 其原理是一次启动所有过程,然后检索控制器的pid,然后将其发送给所有工人,以便他们可以开始工作。代码如下所示: defmodule XYZ.MySup do use Supervisor def start_link(opts) do ... end def init(:ok) do children = [ {
defmodule XYZ.MySup do
use Supervisor
def start_link(opts) do
...
end
def init(:ok) do
children = [
{XYZ.Controller, name: :ctrl},
%{id: XYZ.Worker_1,
start: {XYZ.Worker,
:start_link, [[name: :w1, args: {"arg_1"}]]}},
... some other workers ...
]
Supervisor.init(children, strategy: :one_for_one)
ch = Supervisor.which_children(self())
...
end
end
defmodule MyApp.Supervisor do
use Supervisor
def start_link do
# Name your supervisor `MyApp.Supervisor`
Supervisor.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
children = [
worker(MyApp.Worker, [])
]
supervise(children, strategy: :simple_one_for_one)
end
end
行Supervisor.which_children(self())
生成进程试图调用自身的错误**(EXIT)
首先启动控制器
其原理是启动控制器,然后获取其pid,然后以控制器的pid作为参数启动工人(顺便说一句,这是首选方法)
Supervisor.which_children(self))
Supervisor.start_child(self(),
%{id: XYZ.Worker_3,
start: {XYZ.Worker,
:start_link, [[name: :w3, args: {"arg_3"}]]}})
失败,出现错误**(退出)进程试图调用自身
我做错了什么?好的,因此当主管已经在处理消息时,您不能向其发送消息。在这种情况下,它是start_link/init消息。就像Elixir/Erlang中的所有内容一样,所有内容都是一个过程,一次只能处理一条消息。本质上,通过在
init
调用中执行此操作,您正在创建一个锁。这是因为,只有在init函数成功退出并且主管是监督树的一部分时,主管才会开始接受消息。这相当于在GenServer自己的handle\u cast/handle\u call回调中调用对GenServer的cast/call
看起来您还想使用一种:简单的一对一
策略来动态启动工作人员
接下来,您应该命名您的主管,这样您就可以调用它,而无需获取pid
最后,您应该将启动功能包装在应用程序定义内的任务中
就我个人而言,我喜欢这样做:
defmodule XYZ.MySup do
use Supervisor
def start_link(opts) do
...
end
def init(:ok) do
children = [
{XYZ.Controller, name: :ctrl},
%{id: XYZ.Worker_1,
start: {XYZ.Worker,
:start_link, [[name: :w1, args: {"arg_1"}]]}},
... some other workers ...
]
Supervisor.init(children, strategy: :one_for_one)
ch = Supervisor.which_children(self())
...
end
end
defmodule MyApp.Supervisor do
use Supervisor
def start_link do
# Name your supervisor `MyApp.Supervisor`
Supervisor.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
children = [
worker(MyApp.Worker, [])
]
supervise(children, strategy: :simple_one_for_one)
end
end
然后在应用程序定义中使用该任务:
defmodule MyApp.Application do
use Application
def start(_, _) do
import Supervisor.Spec, warn: false
children = [
supervisor(MyApp.WorkerSupervisor, []),
worker(Task, [&on_boot/0], restart: :temporary)
]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
defp on_boot do
child_spec = MyApp.Worker.child_spec(args: [_arg1, _arg2, _arg3], name: :w1)
Supervisor.start_child(MyApp.WorkerSupervisor, child_spec)
# ... more workers
:ok
end
end
我不完全确定上面的child\u spec
调用,因此您可能需要检查文档:
然后,您可以通过调用supervisor.which_children(MyApp.WorkerSupervisor)
在应用程序中的任何其他位置获取主管的孩子
如果要查看生成的监控树,请在iex控制台内使用:observer.start()
,然后单击应用程序
选项卡,这将非常有用