【问题标题】:Naming Elixir GenServer Processes differently from the module that implements themElixir GenServer 进程的命名与实现它们的模块不同
【发布时间】:2016-05-23 20:41:53
【问题描述】:

我有一个名为 Tornado 的模块,它实现了一个 GenServer,我试图将它作为一个名称与模块本身名称不同的进程生成。 根据Elixir Docs,可以通过将原子作为参数来注册 GenServer 进程

children = [
  worker(Tornado, [[], [name: :tornado_server]])
]

但是当我尝试调用一个函数时,我得到一个错误:

iex(2)> :tornado_server.send_requests 
** (UndefinedFunctionError) undefined function :tornado_server.send_requests/1 (module :tornado_server is not available)

我也试过把:tornado_server改成TornadoServer

** (UndefinedFunctionError) undefined function     TornadoServer.send_requests/1 (module TornadoServer is not available)

编辑

这里是龙卷风模块

defmodule Tornado do
  use GenServer

  # Public API
  def start_link(state,  opts \\ []) do
    GenServer.start_link __MODULE__, state, opts
  end

  def send_requests(requests) do
    GenServer.cast(self, {:send_requests, requests})
  end

  def get_responses do
    GenServer.call(self, :get_responses )
  end

  # GenServer API
  def init(state) do
    # creaza 10 Ci
    { :ok, state }
  end

  def handle_cast({:send_requests, requests}, state) do
    state = state ++ [{requests, "127.0.0.1\n"}]
    {:noreply, state }
  end

  def handle_call(:get_responses, _from, state) do
    {:reply, state, state}
  end
end

这是启动它的主管:

defmodule TornadoSupervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__,[])
  end

  def init([]) do
    children = [
      worker(Tornado, [[], [name: :tornado_server]])
    ]

    supervise(children, strategy: :one_for_one)
  end
end

基本上我想这样称呼它:

 > TornadoSupervisor.start_link
 > TornadoServer.send_requests some_requests_array
 > TornadoServer.get_responses

稍后编辑 显然,如果我这样做,它会起作用

 > GenServer.cast(TornadoServer, {:send_requests,requests})
 > GenServer.call(TornadoServer, :get_responses )

但是我觉得这个语法太冗长了。

【问题讨论】:

    标签: elixir erlang-otp gen-server


    【解决方案1】:

    使用:tornado_server.send_requests 调用您的函数将查找erlang 模块tornado_server,这不太可能是您想要的。

    你仍然需要在你的模块上调用函数,名称是用来代替 pid,而不是模块名。

    没有看到您的模块,很难进一步提供建议。我建议阅读 http://elixir-lang.org/getting-started/mix-otp/genserver.html 然后阅读 http://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html 以了解命名进程的工作原理。

    编辑

    GenServer.cast/call 期望 pid(或注册名称)作为第一个参数。您正在使用的 pid(self 的结果)是调用者,而不是正在运行的 GenServer。

    您应该存储 pid 并执行以下操作:

    {:ok, pid} = Tornado.start_link()
    Tornado.send_requests(pid, some_requests_array)
    Tornado.get_responses(pid)
    

    或者您应该替换您的实现以使用提供的名称:

      def send_requests(requests) do
        GenServer.cast(:tornado_server, {:send_requests, requests})
      end
    
      def get_responses do
        GenServer.call(:tornado_server, :get_responses )
      end
    

    目前还不清楚为什么您不想使用模块名称。对于您只需要其中一个的 GenSever,这是一个非常常见的约定。

    【讨论】:

    • 我已经添加了实现。希望现在更清楚了
    • "对于 GenSever 来说,这是一个非常常见的约定,您只需要其中一个。"我知道了。实际上还有另一个原因,我想为我的流程使用不同的名称。我有另一个模块Queue,它实现了一个请求队列。我想生成多个队列,每个域名一个队列(Queue.domain1.comQueue.domain2.com 等等)。那里我基本上只有一个模块,但我希望为每个域动态指定进程名称。
    • 你写的第一个解决方案不应该是Tornado(也就是模块的名称)而不是TornadoServer(进程的名称)吗?
    • 第二个解决方案在调用Tornado.send_requests 时有效。谢谢!
    猜你喜欢
    • 2017-10-16
    • 2016-06-24
    • 2016-03-14
    • 1970-01-01
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 2014-11-06
    相关资源
    最近更新 更多