2016-09-07 10 views
1

gen_server 프로세스에서 receive 절을 사용할 수 있습니까? 나는 확장 성을위한 설계의 제 10 장을 읽고 있어요 그것은 말한다 : 저자는 이렇게 말할 수있는 이유는gen_server 프로세스에서 절을 사용할 수 있습니까?

enter image description here

있습니까? 우리가 gen_server와 통신하고 싶다면 우리는 gen_server:call/cast을해야하지만, 우리의 handle_call/cast 부분에 있다면 우리는 receive 절의 힘이 필요합니까? 그것을 사용해도 괜찮습니까?

답변

2

기본적으로 gen_server 호출 (및 gen_fsm)의 시간 제한은 5 초입니다. 콜백 함수는 이유로 너무 오래, 서버 충돌 지속되면

{timeout,{gen_server,call,[GenServerPid,LastMessage]}}

그것은하지 않습니다 캐스트 기능, 동시에 아웃 (콜백 즉시 반환하기 때문에 내가 추측)가 보인다 있지만, 콜백 실행에 의해 차단 된 경우 다음 호출이 실패하게됩니다. 응용 프로그램이

(두 번째 메시지의 부족이 오류 상태임을 고려한다면 즉) 메시지가 콜백하는 동안 곧 도착할 것을 요구하지 않는

그래서 나는 그것이 좋은 아이디어라고 생각하지 않습니다

-module (tout). 

-behaviour(gen_server). 

-define(SERVER, ?MODULE). 

%% export interfaces 
-export([start_link/0,call/2,cast/2]). 

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

%% INTERFACES %% 

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

call(Pid,Time) -> 
    gen_server:call(Pid,{wait,Time}). 

cast(Pid,Time) -> 
    gen_server:cast(Pid,{wait,Time}). 

%% CALLBACK FUNCTIONS %% 

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

handle_call({wait,Time}, _From, State) -> 
    timer:sleep(Time), 
    {reply, done, State}; 
handle_call(_Request, _From, State) -> 
    {reply, {error, unknown_call}, State}. 

handle_cast({wait,Time}, State) -> 
    timer:sleep(Time), 
    {noreply, State}; 
handle_cast(_Msg, State) -> 
    {noreply, State}. 

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

terminate(_Reason, _State) -> 
    ok. 

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

%% LOCAL FUNCTIONS %% 

셸 세션 :

1> c(tout).      
{ok,tout} 
2> tout:start_link().   
{ok,<0.136.0>} 
3> tout:call(tout,500).   
done 
4> tout:call(tout,5100).   
** exception exit: {timeout,{gen_server,call,[tout,{wait,5100}]}} 
    in function gen_server:call/2 (gen_server.erl, line 204) 
5> tout:start_link(). 
{ok,<0.141.0>} 
6> tout:cast(tout,10000). 
ok 
7> tout:cast(tout,1000). 
ok 
8> % wait a little . 
8> tout:call(tout,100). 
done 
9> tout:cast(tout,10000). 
ok 
10> % no wait . 
11> tout:call(tout,100). 
** exception exit: {timeout,{gen_server,call,[tout,{wait,100}]}} 
    in function gen_server:call/2 (gen_server.erl, line 204) 
12> 

[편집]다음 코드를 확인 예 선택적 수신는 gen_fsm 불가능하고 일반적인 문제는 다음과 같습니다

FSM은 STATE_1에 있으며 state_2로 이동하라는 메시지가 다음 도착하기 직전, state_2에서 처리해야하는 메시지 수신 :

  • 이 첫 번째 메시지는 state_1에서 처리해야합니다. 그렇지 않으면 프로세스가 충돌합니다.
  • 이 메시지는 사서함에서 제거되며 fsm이 State2로 전환 할 때 여기에 없으므로 응용 프로그램은이 위험을 관리해야합니다. 하나의 프로세스에 의해 올바른 순서로 2 개의 메시지를 전송함으로써 상황을 파악할 수 있습니다.

이 문제는 프로세스가 gen_fsm 코드를 실행하는 동안이 문제가 2 콜백 사이에 표시되므로 콜백 중 하나의 수신 블록에서 해결할 수 없습니다.

내가는 R19에서 오는 새로운 행동 gen_statem 해결해야 할 문제 중 하나입니다 생각 handle_call에서 receive을 사용하고 다른 콜백 이유

+0

제 경우에는 gen_server에 대한 호출이 없으며 모든 작업은 캐스트를 통해 수행됩니다. 타임 아웃에 대해 옳은 것 같아요. 그렇다고해서 저자가 그렇게 말하는 이유는 아닌 것 같습니다. –

+0

답변을 수정했습니다. – Pascal

3

Pascal's answer 당신을 알려줍니다 (나는 그것이 비록 매우 빠른 읽기) 또는 좋은 생각이 아닐 수도 있습니다. 저자가 그 문장에서 의미하는 바가 아니라는 점에 주목하십시오.요점은 A와 B라는 두 개의 메시지를 예상하고 어느 메시지가 먼저 도착할지 모르지만 A 앞에 B를 처리하려는 경우 receive :

wait_for_a() -> 
    receive 
     {a, A} -> 
      process_a(A), 
      wait_for_b() 
    end. 

wait_for_b() -> 
    receive 
     {b, B} -> 
      process_b(B) 
    end. 
으로 쉽게 수행 할 수 있다는 것입니다.

그러나 프로세스가 gen_server 또는 gen_fsm 인 경우 다음과 같은 작업을 수행 할 수 없습니다. 콜백 함수가 수신 메시지를 순서대로 호출하고 이후 처리를 위해 메시지 B를 지연하려는 경우 귀하의 주 또는 다른 곳에서 그것을 저장하십시오.


handle_call/handle_castreceive를 사용할 때 고려해야 할 또 다른 것은 당신이 이론적으로는 처리 할 준비를해야 system messages을받을 수 있다는 것입니다.

+2

문장을 다시 읽고, 나는 당신이 옳다고 생각하고, 저자는'receive'에 대해서 말하지 않고 있으며,'receive'를 사용하지 않고'handle_call'에 대해 이야기하고 있습니다. 시스템 메시지에 관해서는, 나는 그들에 대해 걱정할 필요가 없다고 생각한다 - receive 절에서 그것들을 일치시키지 않는 한, 그들은 다른 컴포넌트에 의해 처리되기를 기다리는 메일 박스에 남아있을 것이다. –

+2

저는이 책의 공동 저자 중 한 명이며, @ legoscia의 해석은 우리가 의미 한 바입니다. 그럼에도 불구하고 @Pascal과 @legoscia 모두 여기에 아주 좋은 조언을 제공합니다. 나는 표준 행동에서'수신 '을 사용할 수 있는지 여부를 묻는 대신 실제 상황을 정확히 설명 할 수있는 별도의 질문을 제시함으로써 실행 가능한 대안을 제공 할 수 있다고 제안했다. . –