Erlang Language
gen_server व्यवहार
खोज…
टिप्पणियों
gen_server
Erlang की एक महत्वपूर्ण विशेषता है, और इस कार्यक्षमता के हर पहलू को समझने के लिए कुछ आवश्यक आवश्यकता है:
एरलांग में एक विशेषता के बारे में अधिक जानने का एक अच्छा तरीका आधिकारिक गिथुब भंडार से स्रोत कोड को सीधे पढ़ना है । gen_server
व्यवहार उपयोगी जानकारी और रोचक संरचना को इसके मूल में एम्बेड करता है।
gen_server
को gen_server
में परिभाषित किया gen_server.erl
और इसके संबद्ध प्रलेखन को stdlib
Erlang प्रलेखन में stdlib
जा सकता है। gen_server
एक OTP सुविधा है और अधिक जानकारी OTP डिज़ाइन सिद्धांत और उपयोगकर्ता की मार्गदर्शिका में भी देखी जा सकती है।
फ्रैंक हेबर्ट ने आपको अपनी मुफ्त ऑनलाइन पुस्तक gen_server
लिए एक और अच्छा परिचय दिया है ।
gen_server
कॉलबैक के लिए आधिकारिक दस्तावेज:
नमस्कार सेवा
यहाँ एक सेवा का उदाहरण दिया गया है जो लोगों को दिए गए नाम से अभिवादन करता है, और इसका सामना करता है कि कितने उपयोगकर्ताओं ने इसका सामना किया। नीचे उपयोग देखें।
%% greeter.erl
%% Greets people and counts number of times it did so.
-module(greeter).
-behaviour(gen_server).
%% Export API Functions
-export([start_link/0, greet/1, get_count/0]).
%% Required gen server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-record(state, {count::integer()}).
%% Public API
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, {}, []).
greet(Name) ->
gen_server:cast(?MODULE, {greet, Name}).
get_count() ->
gen_server:call(?MODULE, {get_count}).
%% Private
init({}) ->
{ok, #state{count=0}}.
handle_cast({greet, Name}, #state{count = Count} = State) ->
io:format("Greetings ~s!~n", [Name]),
{noreply, State#state{count = Count + 1}};
handle_cast(Msg, State) ->
error_logger:warning_msg("Bad message: ~p~n", [Msg]),
{noreply, State}.
handle_call({get_count}, _From, State) ->
{reply, {ok, State#state.count}, State};
handle_call(Request, _From, State) ->
error_logger:warning_msg("Bad message: ~p~n", [Request]),
{reply, {error, unknown_call}, State}.
%% Other gen_server callbacks
handle_info(Info, State) ->
error_logger:warning_msg("Bad message: ~p~n", [Info]),
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
यहाँ इस सेवा का एक नमूना है जो एर्लांग खोल में है:
1> c(greeter).
{ok,greeter}
2> greeter:start_link().
{ok,<0.62.0>}
3> greeter:greet("Andriy").
Greetings Andriy!
ok
4> greeter:greet("Mike").
Greetings Mike!
ok
5> greeter:get_count().
{ok,2}
Gen_server व्यवहार का उपयोग करना
एक gen_server
एक विशिष्ट परिमित स्टेट मशीन है जो सर्वर की तरह काम करती है। gen_server
विभिन्न प्रकार के ईवेंट को संभाल सकता है:
-
handle_call
साथ तुल्यकालिक अनुरोध -
handle_cast
साथ एसिंक्रोनस अनुरोध - अन्य संदेश (ओटीपी विनिर्देश में परिभाषित नहीं)
handle_info
साथ
सिंक्रोनस और एसिंक्रोनस संदेश ओटीपी में निर्दिष्ट हैं और इस पर किसी भी तरह के डेटा के साथ सरल टैग किए गए टुपल्स हैं।
एक साधारण gen_server
को इस तरह परिभाषित किया गया है:
-module(simple_gen_server).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
start_link() ->
Return = gen_server:start_link({local, ?MODULE}, ?MODULE, [], []),
io:format("start_link: ~p~n", [Return]),
Return.
init([]) ->
State = [],
Return = {ok, State},
io:format("init: ~p~n", [State]),
Return.
handle_call(_Request, _From, State) ->
Reply = ok,
Return = {reply, Reply, State},
io:format("handle_call: ~p~n", [Return]),
Return.
handle_cast(_Msg, State) ->
Return = {noreply, State},
io:format("handle_cast: ~p~n", [Return]),
Return.
handle_info(_Info, State) ->
Return = {noreply, State},
io:format("handle_info: ~p~n", [Return]),
Return.
terminate(_Reason, _State) ->
Return = ok,
io:format("terminate: ~p~n", [Return]),
ok.
code_change(_OldVsn, State, _Extra) ->
Return = {ok, State},
io:format("code_change: ~p~n", [Return]),
Return.
यह कोड सरल है: प्राप्त प्रत्येक संदेश मानक आउटपुट पर मुद्रित होता है।
gen_server व्यवहार
एक gen_server
को परिभाषित करने के लिए, आपको अपने स्रोत कोड में -behaviour(gen_server)
के साथ स्पष्ट रूप से घोषित करने की आवश्यकता है। ध्यान दें, behaviour
यूएस (व्यवहार) या यूके (व्यवहार) में लिखा जा सकता है।
start_link / 0
यह फ़ंक्शन किसी अन्य फ़ंक्शन को कॉल करने के लिए एक सरल शॉर्टकट है: gen_server:start_link/3,4
।
start_link / 3,4
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
यह फ़ंक्शन तब कहा जाता है जब आप अपने सर्वर को supervisor
या किसी अन्य प्रक्रिया से लिंक करना शुरू करना चाहते हैं। start_link/3,4
आपकी प्रक्रिया को स्वचालित रूप से पंजीकृत कर सकता है (यदि आपको लगता है कि आपकी प्रक्रिया अद्वितीय होने की आवश्यकता है) या बस इसे सरल प्रक्रिया की तरह स्पॉन कर सकते हैं। जब कहा जाता है, यह फ़ंक्शन init/1
निष्पादित करता है।
यह फ़ंक्शन इन परिभाषित मानों को वापस कर सकता है:
-
{ok,Pid}
-
ignore
-
{error,Error}
init / 1
init([]) ->
State = [],
{ok, State}.
init/1
पहला निष्पादित कार्य है जब आपका सर्वर लॉन्च किया जाएगा। यह आपके एप्लिकेशन की सभी शर्त को इनिशियलाइज़ करता है और नए बनाए गए प्रोसेस में वापस आ जाता है।
यह फ़ंक्शन केवल इन परिभाषित मूल्यों को वापस कर सकता है:
-
{ok,State}
-
{ok,State,Timeout}
-
{ok,State,hibernate}
-
{stop,Reason}
-
ignore
State
वेरिएबल सब कुछ हो सकता है, (उदाहरण के लिए सूची, टपल, प्रॉप्लिस्ट्स, मैप, रिकॉर्ड) और स्पैवियर प्रक्रिया के अंदर सभी फ़ंक्शन के लिए सुलभ रहें।
handle_call / 3
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
gen_server:call/2
इस कॉलबैक को निष्पादित करता है। पहला तर्क आपका संदेश ( _Request
) है, दूसरा अनुरोध ( _From
) का मूल है और अंतिम आपके चल रहे gen_server व्यवहार की वर्तमान स्थिति ( State
) है।
यदि आप कॉलर के लिए उत्तर चाहते हैं, तो handle_call/3
को इनमें से एक डेटा संरचना को वापस करने की आवश्यकता है:
-
{reply,Reply,NewState}
-
{reply,Reply,NewState,Timeout}
-
{reply,Reply,NewState,hibernate}
यदि आप कॉलर का कोई उत्तर नहीं चाहते हैं, तो handle_call/3
को इनमें से एक डेटा संरचना को वापस करने की आवश्यकता है:
-
{noreply,NewState}
-
{noreply,NewState,Timeout}
-
{noreply,NewState,hibernate}
यदि आप अपने वर्तमान gen_server के मौजूदा निष्पादन को रोकना चाहते हैं, तो handle_call/3
को इनमें से एक डेटा संरचना को वापस करने की आवश्यकता है:
-
{stop,Reason,Reply,NewState}
-
{stop,Reason,NewState}
handle_cast / 2
handle_cast(_Msg, State) ->
{noreply, State}.
gen_server:cast/2
इस कॉलबैक को निष्पादित करता है। पहला तर्क आपका संदेश ( _Msg
) है, और दूसरा आपके चल रहे gen_server व्यवहार की वर्तमान स्थिति है।
डिफ़ॉल्ट रूप से, यह फ़ंक्शन कॉलर को डेटा नहीं दे सकता है, इसलिए, आपके पास केवल दो विकल्प हैं, वर्तमान निष्पादन जारी रखें:
-
{noreply,NewState}
-
{noreply,NewState,Timeout}
-
{noreply,NewState,hibernate}
या अपनी वर्तमान gen_server
प्रक्रिया को gen_server
:
-
{stop,Reason,NewState}
handle_info / 2
handle_info(_Info, State) ->
{noreply, State}.
handle_info/2
को तब निष्पादित किया जाता है जब गैर-मानक ओटीपी संदेश बाहरी दुनिया से आता है। यह कोई जवाब नहीं दे सकता है और जैसे handle_cast/2
केवल 2 कार्रवाई कर सकता है, वर्तमान निष्पादन जारी रख सकता है:
-
{noreply,NewState}
-
{noreply,NewState,Timeout}
-
{noreply,NewState,hibernate}
या चालू चल रही gen_server
प्रक्रिया को gen_server
:
-
{stop,Reason,NewState}
समाप्त / 2
terminate(_Reason, _State) ->
ok.
जब कोई त्रुटि होती है या जब आप अपनी gen_server
प्रक्रिया को बंद करना चाहते हैं, तो terminate/2
कहा जाता है।
code_change / 3
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
जब आप अपना रनिंग कोड अपग्रेड करना चाहते हैं तो code_change/3
फ़ंक्शन को कहा जाता है।
यह फ़ंक्शन केवल इन परिभाषित मूल्यों को वापस कर सकता है:
-
{ok, NewState}
-
{error, Reason}
इस प्रक्रिया को शुरू करना
आप अपना कोड संकलित कर सकते हैं और simple_gen_server
शुरू कर सकते हैं:
simple_gen_server:start_link().
यदि आप अपने सर्वर को संदेश भेजना चाहते हैं, तो आप इन कार्यों का उपयोग कर सकते हैं:
% will use handle_call as callback and print:
% handle_call: mymessage
gen_server:call(simple_gen_server, mymessage).
% will use handle_cast as callback and print:
% handle_cast: mymessage
gen_server:cast(simple_gen_server, mymessage).
% will use handle_info as callback and print:
% handle_info: mymessage
erlang:send(whereis(simple_gen_server), mymessage).
सरल कुंजी / मूल्य डेटाबेस
यह स्रोत कोड map
Erlang datastructure के आधार पर एक साधारण कुंजी / मान स्टोर सेवा बनाता है। सबसे पहले, हमें अपने gen_server
संबंधित सभी जानकारी को परिभाषित करने की आवश्यकता है:
-module(cache).
-behaviour(gen_server).
% our API
-export([start_link/0]).
-export([get/1, put/2, state/0, delete/1, stop/0]).
% our handlers
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
% Defining our function to start `cache` process:
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
%%%%%%%%%%%%%%
% API
% Key/Value database is a simple store, value indexed by an unique key.
% This implementation is based on map, this datastructure is like hash
# in Perl or dictionaries in Python.
% put/2
% put a value indexed by a key. We assume the link is stable
% and the data will be written, so, we use an asynchronous call with
% gen_server:cast/2.
put(Key, Value) ->
gen_server:cast(?MODULE, {put, {Key, Value}}).
% get/1
% take one argument, a key and will a return the value indexed
% by this same key. We use a synchronous call with gen_server:call/2.
get(Key) ->
gen_server:call(?MODULE, {get, Key}).
% delete/1
% like `put/1`, we assume the data will be removed. So, we use an
% asynchronous call with gen_server:cast/2.
delete(Key) ->
gen_server:cast(?MODULE, {delete, Key}).
% state/0
% This function will return the current state (here the map who contain all
% indexed values), we need a synchronous call.
state() ->
gen_server:call(?MODULE, {get_state}).
% stop/0
% This function stop cache server process.
stop() ->
gen_server:stop(?MODULE).
%%%%%%%%%%%%%%%
% Handlers
% init/1
% Here init/1 will initialize state with simple empty map datastructure.
init([]) ->
{ok, #{}}.
% handle_call/3
% Now, we need to define our handle. In a cache server we need to get our
% value from a key, this feature need to be synchronous, so, using
% handle_call seems a good choice:
handle_call({get, Key}, From, State) ->
Response = maps:get(Key, State, undefined),
{reply, Response, State};
% We need to check our current state, like get_fea
handle_call({get_state}, From, State) ->
Response = {current_state, State},
{reply, Response, State};
% All other messages will be dropped here.
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
% handle_cast/2
% put/2 will execute this function.
handle_cast({put, {Key, Value}}, State) ->
NewState = maps:put(Key, Value, State),
{noreply, NewState};
% delete/1 will execute this function.
handle_cast({delete, Key}, State) ->
NewState = maps:remove(Key, State),
{noreply, NewState};
% All other messages are dropped here.
handle_cast(_Msg, State) ->
{noreply, State}.
%%%%%%%%%%%%%%%%
% other handlers
% We don't need other features, other handlers do nothing.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
हमारे कैश सर्वर का उपयोग करना
अब हम अपने कोड को संकलित कर सकते हैं और इसे erl
साथ उपयोग करना शुरू कर सकते हैं।
% compile cache
c(cache).
% starting cache server
cache:start_link().
% get current store
% will return:
% #{}
cache:state().
% put some data
cache:put(1, one).
cache:put(hello, bonjour).
cache:put(list, []).
% get current store
% will return:
% #{1 => one,hello => bonjour,list => []}
cache:state().
% delete a value
cache:delete(1).
cache:state().
% #{1 => one,hello => bonjour,list => []}
% stopping cache server
cache:stop().