Erlang,尝试制作gen_server:调用许多回复

时间:2015-10-15 12:32:26

标签: erlang otp gen-server

尝试在项目中使用OTP样式并获得一个OTP接口问题。什么解决方案更受欢迎/更美观?

我有什么:

  1. 使用mochiweb
  2. 的网络服务器
  3. 一个过程,产生了许多(1000-2000)个孩子。 儿童包含状态(净流速)。如果需要,处理代理消息给子节点并创建新子节点。
  4. 在mochiweb中,我有一个页面,所有演员的速度,乳清是如何制作的:

        nf_collector ! {get_abonents_speed, self()},
        receive
            {abonents_speed_count, AbonentsCount} ->
                ok
        end,
    %% write http header, chunked
    %% and while AbonentsCount != 0,  receive speed and write http
    

    这不是-opt风格,我怎么理解。解决方案:

    1. 在API同步功能中,以速度获取所有请求,并以所有速度返回列表。但我想立刻把它写给客户。
    2. API函数的一个参数是回调:

      nf_collector:get_all_speeds(fun (Speed) -> Resp:write_chunk(templater(Speed)) end)
      
    3. 返回迭代器: get_all_speeds的结果之一将与receive-block一起使用。每次调用都会返回{ok, Speed},最后会返回{end}
    4. get_all_speeds() ->
          nf_collector ! {get_abonents_speed, self()},
          receive
              {abonents_speed_count, AbonentsCount} ->
                  ok
          end,
          {ok, fun() -> 
              create_receive_fun(AbonentsCount)
          end}.
      
      create_receive_fun(0)->
          {end};
      
      create_receive_fun(Count)->
              receive
                  {abonent_speed, Speed} ->
                      Speed
              end,
              {ok, Speed, create_receive_fun(Count-1)}.
      

1 个答案:

答案 0 :(得分:1)

产生你的孩子'来自主管:

GET /boards/([^/]+)(?!lists)

用ch_sup启动它们:start_child / 1(数据是什么)。

将您的孩子实现为gen_server:

-module(ch_sup).
-behaviour(supervisor).
-export([start_link/0, init/1, start_child/1]).
start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) -> {ok, {{simple_one_for_one}, [{ch, {ch, start_link, []}, transient, 1000, worker, [ch]}]}}.
start_child(Data) -> supervisor:start_child(?MODULE, [Data]).

...

-module(ch).
-behaviour(gen_server).
-record(?MODULE, {speed}).

...

get_speed(Pid, Timeout) ->
    try
        gen_server:call(Pid, get, Timeout)
    catch
        exit:{timeout, _} -> timeout;
        exit:{noproc, _} -> died
    end
.

您现在可以使用主管获取正在运行的孩子的列表并查询它们,尽管您必须接受孩子在获取孩子名单和打电话给他们之间死亡的可能性,显然孩子可能由于某种原因活着但没有回应,或者回答错误等等。

上面的get_speed / 2函数返回{ok,Speed}或者死亡或超时。您仍可根据应用需求进行适当过滤;列表理解很容易,这里有一些。

只是速度:

handle_call(get, _From, St) -> {reply, {ok, St#?MODULE.speed}, St} end.

Pid和速度元组:

[Speed || {ok, Speed} <- [ch:get_speed(Pid, 1000) || Pid <-
    [Pid || {undefined, Pid, worker, [ch]} <-
        supervisor:which_children(ch_sup)
        ]
    ]].

所有结果,包括超时和&#39;死亡&#39;孩子在你到达之前死亡的结果:

[{Pid, Speed} || {Pid, {ok, Speed}} <-
    [{Pid, ch:get_speed(Pid, 1000)} || Pid <-
        [Pid || {undefined, Pid, worker, [ch]} <-
                supervisor:which_children(ch_sup)]
        ]
    ].

在大多数情况下,除了速度之外,你几乎肯定不需要任何其他东西,因为你会对死亡和超时做些什么呢?你希望那些死亡的人被主管重生,所以问题或多或少地在你知道它的时候得到解决,超时和任何错误一样,是一个单独的问题,无论你以何种方式处理适合......不需要将故障修复逻辑与数据检索逻辑混合在一起。

现在,我认为你在帖子中得到的所有这些问题,但我不太确定,每次通话的超时时间为1000,每次通话都是同步的另一方面,对于1000名1秒钟超时的孩子,可能需要1000秒才能产生结果。使时间超时1ms可能是答案,但要正确地做到这一点有点复杂:

[{Pid, Any} || {Pid, Any} <-
    [{Pid, ch:get_speed(Pid, 1000)} || Pid <-
        [Pid || {undefined, Pid, worker, [ch]} <-
                supervisor:which_children(ch_sup)]
        ]
    ].

此处每次通话都会在不同的流程中产生并收集回复,直到主人超时为止。或者他们都被收到了。

代码大部分都是从我周围的各种作品中剪下来的,然后手动编辑并通过搜索替换,将其匿名化并删除剩余部分,因此它可能主要是可编辑的质量,但我不是&# 39;我保证我没有破坏任何东西。