在gen_servers中如何选择性接收? [英] How do you do selective receives in gen_servers?

查看:90
本文介绍了在gen_servers中如何选择性接收?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将我的大部分应用程序移植到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,
终止/ 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) - >
回复= ok,
{reply,Reply,State}。

handle_cast(test,_State) - >
列表: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}。

终止(_Reason,_State) - >
好​​的。

code_change(_OldVsn,State,_Extra) - >
{ok,State}。

当然,在我的真实应用中,有定时器延迟和需要处理的消息顺序与其他消息交错。特别地,我发送http请求,有时候很多,有时一次,间隔一段时间。无论如何,我需要按顺序收集。

解决方案

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

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

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

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

handle_results([W | WTail] = Wait,Buff) - >
案例列表:
的成员(W,Buff)为true - >
io:format(result:++ integer_to_list(W)++〜n),
handle_results(WTail,Buff - [W]);
false - >
{等等,Buff}
结束。


I ported most of my app to OTP behaviors, but I'm stuck. I can't figure out how to do selective receives using a gen_server. If none of the callback function clauses match a message, rather than putting the message back in the mailbox, it errors out!

Now, everywhere I go, folks laud selective receives. Everywhere I go, folks laud OTP. Can it really be true that you can't have both at once? Doesn't this seem like a major, correctable shortcoming?

How do erlang programmers handle this?

EDIT (responding to zed's comment):

Here's an example where I'd like to see a list of integers printed in sorted order:

-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}.

Of course, in my real app, there are timer delays and the messages that need to be processed in order are interleaved with other messages. In particular, I send out http requests, sometimes many at once, sometimes one at a time with an interval between them. In any case, I need to collect them in order.

解决方案

Gen_server is probably not the best choice for this. One thing you can do is to receive all messages into a buffer list, and implement the selective receive yourself:

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.

这篇关于在gen_servers中如何选择性接收?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆