2009-08-17 5 views
7

저는 대부분의 앱을 OTP 동작으로 이식했지만 막혔습니다. gen_server를 사용하여 선택적 수신을 수행하는 방법을 알아낼 수 없습니다. 콜백 함수 절이 하나도없는 경우 메시지를 사서함에 다시 저장하는 대신 오류가 발생합니다.gen_servers의 선택 수신은 어떻게합니까?

이제 모든 곳에서 내가 선택한 사람들은 선량을 칭찬합니다. 내가가는 곳마다 사람들은 OTP를 자랑합니다. 한 번에 둘 다 가질 수는 없다는 것이 사실 일 수 있습니까? 이것은 주요한 수정 가능한 단점처럼 보이지 않습니까?

어떻게 erlang 프로그래머가 이것을 처리합니까?

편집 (의 데이빗 주석에 응답) :

은 여기가 정렬 된 순서로 인쇄 된 정수의 목록을보고 싶어요 예입니다 : 내 실제 응용 프로그램에서, 물론

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

을, 타이머 지연이 있고 순서대로 처리해야하는 메시지는 다른 메시지와 인터리브됩니다. 특히 HTTP 요청을 한 번에 한 번에 한 번에 한 번에 한 번씩 한 번에 하나씩 보내 게됩니다. 어쨌든 나는 그것을 순서대로 수집해야한다.

+0

달성하고자하는 것은 무엇입니까? – 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. 
+0

완벽을 기하기 위해 원하지 않는 모든 메시지를 사용자 본인에게 다시 보낼 수 있습니다 (사서함의 끝으로 이동). 이것은 많은 문제가 있습니다 (gen_server는 메시지를 앞뒤로 풀 스로틀로 움직이게되며, 구현의 구체적인 내용을 사용합니다). 그러므로 사용해서는 안됩니다 : handle_cast (Msg, State) -> self()! { '$ gen_cast', Msg}, {noreply, State}입니다. – Zed

+0

그래, 나는 이것을 더 일찍 생각했다. 아주 짧게. ;) 첫 번째 아이디어는 좋은 아이디어입니다. 일반적으로 처리하기 전에 8 개 항목을 수집해야합니다. 일자리에는 일반적으로 200 배치가 있습니다. 나는 당신의 방법이 숫자로 각 결과에 태깅하고 8 개의 항목이 수신되면 각 배치를 분류하는 것보다 효율적인지 여부를 계산하려고합니다. – mwt

3

어쩌면 당신이 정말로 gen_fsm를 사용하려면 : 당신이 할 수있는 한 가지 선택이 스스로를 수신 버퍼 목록에 모든 메시지를 수신하고 구현하는 것입니다. 이 동작은 일반적으로 프로토콜이 특정 상태를 가지며 현재 상태에 따라 요청을 다르게 처리해야하는 프로토콜의 프론트 엔드로 선택됩니다. 그러나 gen_server로 돌아가서 해당 기능에 gen_server를 사용합니다. 코드 로딩을위한 시스템 이벤트를 구독하고 code_change 콜백을 제공합니다. 충돌에 대한 sasl-reports가 발생합니다. 코드 유지 관리에 도움이되는 잘 알려진 구조가 있습니다. 가장 중요한 것은 동기식 호출을 위해 잘 설계된 프로토콜을 구현한다는 것입니다.

이 경우 OTP 동작이 적합한 지 아닌지를 말하기가 어렵습니다.


의견을 제시하면 gen_server가 잘못된 것처럼 들립니다. gen_server 동작을 사용할 때 저는 회사의 보스라고 생각합니다. 모두가 상사와 이야기하기를 원하므로 상사가 업무를 신속하고 효율적으로 위임 할 수있게하여 회사원들이 사람들이 일하는 대신 기다리는 것을 허용하지 않도록하는 것이 가장 좋습니다.

gen_server는 '보낸 사람'매개 변수를 사용하여 위임 할 수 있습니다. 이렇게하려면 {no_reply, State}을 반환하고 From 매개 변수를 대리인에게 전달합니다. 대표는 gen_server:reply/2을 사용하여 원래 호출에 응답합니다.

gen_server를 사용하는이 방법은 아마도 당신을위한 것일 수 있습니다. 선택적 수신을 위해 수신 종료를 사용하는 "일반"프로세스를 시작하십시오. 이것이 진정으로 독립적 인 직업이라면 gen_server는 그것을 무시할 수 있습니다 (화재와 잊기). 완료되었는지 알기를 원하면 gen_server:cast/2 메시지를 시작된 "일반"프로세스에서 다시 확인할 수 있습니다.

선택적 수신을 수행하는 동안 gen_server를 차단하려면 프로세스를 시작하고 돌아 오기 전에 죽을 때까지 기다리는 것이 좋습니다. 선택적 수신은 도착한 순서대로 메시지에 대한 O (n) 선형 탐색입니다. 따라서 각각의 선택적 수신은 인기있는 gen_server에 대해 높을 수있는 대기중인 모든 메시지를 검색합니다.

아무도 회사에서 일하는 상사 만 있으면 안됩니다. erlang 어플리케이션은 gen_servers만을 가지고 있다고 가정하지 않습니다.

+0

gen_fsm은 흥미로운 아이디어입니다. 저는 그것을 사용하기위한 변명 거리를 찾고있었습니다. 처음에는 어떤 식 으로든 국가를 "매개 변수화"할 수 없다면, 그것이 저에게 효과가있을 것이라고 생각하지 않습니다. 전형적인 경우는 8 개 주이지만 수백 개의 경우가 있습니다. gen_fsm이 그런 의미인지는 모르겠다. 정말 OTP 기능을 원합니다. gen_servers가 자연스럽게 그것을 수행 할 수 없다는 점을 감안할 때, 다른 방식으로 선택적 수신을 처리 할 것입니다. – mwt

2

모듈 중 하나에 gen_server를 사용할 수 없다고해서 OTP를 사용하지 않는다는 의미는 아닙니다. 모든 콜백 모듈은 선택적 수신을 사용할 수 없게하는 수신 블록을 구현합니다. 선택적 수신을 처리하는 자체 서비스를 구현할 수있는 이유가 없습니다. 그렇게하는 것이 OTP 방식으로하지 않았 음을 의미하지는 않습니다.

귀하는 여전히 모든 혜택을 제공하는 관리자가 서비스를 관리 할 수 ​​있습니다.

4

아니요, gen_server는 선택적 수신을 처리 할 수 ​​있도록 설계되지 않았으므로 각 요청은 수신 된대로 처리됩니다. Erlang은 모든 패턴이 컴파일 타임에 알려 지도록 요구하기 때문에 실제로는 어려운 문제입니다. "패턴 객체"가 없습니다.

gen_fsm은 상태 수가 폭발하기 전에 gen_fsm이 취하지 않기 때문에 다른 메시지가 어떤 순서로 도착할 수도 있으므로 동의하지 않을 수도 있습니다. 이것이 선택 수신을 추가 한 이유 중 하나 였으므로 나중에 관심없는 메시지를 무시하고 안전하게 무시할 수 있습니다.

어떤 OTP에 관심이 있습니까?

+0

OTP 기능을 의미하는 경우, sys : get_status와 같은 디버깅 작업을 좋아합니다. 그것은 이미 정말로 편리했습니다. 그리고 sasl에서 오는 충돌 보고서는 매우 귀중한 것입니다. 그리고 프로세스가 감독되기를 원합니다. 보통 프로세스를 사용하면 쉽게 처리 할 수 ​​있습니다. 그리고 나는 좀더 저의 프로세스를 gen_server API로 호출하는 아이디어를 좋아했습니다. 가장 큰 일은 이것이 내 첫 번째 주요한 erlang 프로젝트이며 마감일이며 OTP는 올바른 길로 보인다는 것입니다. 모든 틈새를 헤쳐 나갈 시간이 없기 때문에 모든 이점을 얻도록 노력하고 싶습니다. – mwt

+0

즉, 가능한 한 응용 프로그램 프레임 워크를 준수하여 이점이 무엇인지 이해할 수 있습니다. 또한 아직 릴리스 업그레이드 처리를하지 못했고 gen_servers를 사용하는 것이 이점이 있다고 생각합니다. – mwt

관련 문제