你如何在gen_servers中进行选择性接收?

mwt*_*mwt 7 erlang

我把我的大部分应用移植到了OTP行为,但是我被卡住了.我无法弄清楚如何使用gen_server进行选择性接收.如果没有回调函数子句与消息匹配,而不是将消息放回邮箱中,则会出错!

现在,无论我走到哪里,人们都会选择接受.我去的每个地方,人们都称赞OTP.你真的不能同时拥有这两个吗?这不是一个重大的,可纠正的缺点吗?

erlang程序员如何处理这个问题?

编辑(回应zed的评论):

这是一个示例,我希望看到按排序顺序打印的整数列表:

-module(sel_recv).
-behaviour(gen_server).

-export([start_link/0]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     terminate/2, code_change/3]).

-export([test/0]).

start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

test() ->
    gen_server:cast(?MODULE, test).

init([]) ->
    {ok, 0}.

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast(test, _State) ->
    lists:map(fun(N) ->
                      gen_server:cast(?MODULE, {result, N})
              end, [9,8,7,6,5,4,3,2,1]),
    {noreply, [1,2,4,5,6,7,8,9]};
handle_cast({result, N}, [N|R]) ->
    io:format("result: " ++ integer_to_list(N) ++ "~n"),
    {noreply, R}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.
Run Code Online (Sandbox Code Playgroud)

当然,在我的真实应用程序中,存在计时器延迟,并且需要按顺序处理的消息与其他消息交错.特别是,我发送了http请求,有时是多次发送,有时一次发送一次,间隔时间间隔.无论如何,我需要按顺序收集它们.

goe*_*tor 7

"plain_fsm"允许您在仍然符合OTP的情况下进行选择性接收.

http://github.com/esl/plain_fsm


Zed*_*Zed 4

Gen_server 可能不是最好的选择。您可以做的一件事是将所有消息接收到缓冲区列表中,并自己实现选择性接收:

handle_cast(test, _State) ->
    ...
    {noreply, {[1,2,4,5,6,7,8,9], []}};

handle_cast({result, N}, {Wait, Buff}) ->
    {noreply, handle_results(Wait, [N|Buff])}.

handle_results([], Buff) ->
    {[], Buff};

handle_results([W|WTail] = Wait, Buff) ->
    case lists:member(W, Buff) of
        true ->
            io:format("result: " ++ integer_to_list(W) ++ "~n"),
            handle_results(WTail, Buff -- [W]);
        false ->
            {Wait, Buff}
    end.
Run Code Online (Sandbox Code Playgroud)