【发布时间】:2015-01-17 19:40:40
【问题描述】:
我在自动启动监督树时遇到了死锁问题。一个 GenServer 的初始状态是树中另一个主管的子工作者。代码如下:
主管和工人:
defmodule Parallel.Worker.Supervisor do
import Supervisor.Spec
def start_link do
# Start up a worker for each core
schedulers = :erlang.system_info(:schedulers)
children = Enum.map(1..schedulers,
&(worker(Parallel.Worker.Server, [], id: "Parallel.Worker#{&1}")))
opts = [strategy: :one_for_one, name: Parallel.Worker.Supervisor]
Supervisor.start_link(children, opts)
end
def workers do
Process.whereis(Parallel.Supervisor)
|> Supervisor.which_children
|> Enum.reduce [], fn
{_name, pid, :worker, _module}, acc -> [{make_ref, pid} | acc]
_, acc -> acc
end
end
end
具有这些工作进程 pid 状态的 GenServer:
defmodule Parallel.Process.Server do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, workers: [Parallel.Worker.Supervisor.workers])
end
end
正如您在最后一行看到的,我正在调用“Parallel.Worker.Supervisor.workers”,这似乎阻止了在树上等待初始化,直到此方法返回才会完成。如何将受监督的 PID 作为初始 GenServer 状态?
更新:
我不想使用 poolboy(尽管查看源代码是一个很好的建议)来帮助我了解更多信息。我并不想特别做任何事情,我的工作人员只是用它的参数处理一个传递的函数。这里是工人 GenServer:
defmodule Parallel.Worker do
use GenServer
require Logger
def start_link(state) do
GenServer.start_link(__MODULE__, state, [])
end
def init(state) do
{:ok, state}
end
# Using cast to be async as the job could take longer than the default 5 seconds,
# Don't want client blocked on waiting for job to complete
def handle_cast({:execute, fun, args, return_pid, job_ref}, state) do
Logger.debug fn()-> "#{inspect self}: Recevied job with args: #{inspect args} for job #{inspect job_ref} to return to #{inspect return_pid}" end
send(return_pid, {job_ref, apply(fun, args), self})
{:noreply, state}
end
end
【问题讨论】:
-
也许您需要重新架构应用程序而不显式传递工作进程 pid。您真正想在这里完成什么?
-
您是否正在寻找像 Poolboy 这样的池化库?查看这篇文章:hashnuke.com/2013/10/03/…
标签: elixir