Erlang 21 - 6. sys and proc_lib

6 sys और proc_lib




erlang

6 sys और proc_lib

sys मॉड्यूल में व्यवहार का उपयोग करके कार्यान्वित प्रक्रियाओं के सरल डिबगिंग के लिए कार्य हैं। इसमें ऐसे फ़ंक्शन भी हैं जो proc_lib मॉड्यूल में फ़ंक्शन के साथ मिलकर एक विशेष प्रक्रिया को लागू करने के लिए उपयोग किया जा सकता है जो एक मानक व्यवहार का उपयोग किए बिना ओटीपी डिज़ाइन सिद्धांतों का अनुपालन करता है। इन कार्यों का उपयोग उपयोगकर्ता-परिभाषित (गैर-मानक) व्यवहारों को लागू करने के लिए भी किया जा सकता है।

दोनों sys और proc_lib STDLIB एप्लिकेशन के हैं।

6.1 सरल डिबगिंग

sys मॉड्यूल में व्यवहार का उपयोग करके कार्यान्वित प्रक्रियाओं के सरल डिबगिंग के लिए कार्य हैं। gen_statem Behaviour से gen_statem Behaviour का उदाहरण इसका वर्णन करने के लिए उपयोग किया जाता है:

Erlang/OTP 20 [DEVELOPMENT] [erts-9.0] [source-5ace45e] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V9.0  (abort with ^G)
1>  code_lock:start_link([1,2,3,4]).
Lock
{ok,<0.63.0>}
2> sys:statistics(code_lock, true).
ok
3>  sys:trace(code_lock, true).
ok
4>  code_lock:button(1).
*DBG* code_lock receive cast {button,1} in state locked
ok
*DBG* code_lock consume cast {button,1} in state locked
5>  code_lock:button(2).
*DBG* code_lock receive cast {button,2} in state locked
ok
*DBG* code_lock consume cast {button,2} in state locked
6>  code_lock:button(3).
*DBG* code_lock receive cast {button,3} in state locked
ok
*DBG* code_lock consume cast {button,3} in state locked
7>  code_lock:button(4).
*DBG* code_lock receive cast {button,4} in state locked
ok
Unlock
*DBG* code_lock consume cast {button,4} in state locked
*DBG* code_lock receive state_timeout lock in state open
Lock
*DBG* code_lock consume state_timeout lock in state open
8> sys:statistics(code_lock, get).
{ok,[{start_time,{{2017,4,21},{16,8,7}}},
     {current_time,{{2017,4,21},{16,9,42}}},
     {reductions,2973},
     {messages_in,5},
     {messages_out,0}]}
9> sys:statistics(code_lock, false).
ok
10> sys:trace(code_lock, false).
ok
11> sys:get_status(code_lock).
{status,<0.63.0>,
        {module,gen_statem},
        [[{'$initial_call',{code_lock,init,1}},
          {'$ancestors',[<0.61.0>]}],
         running,<0.61.0>,[],
         [{header,"Status for state machine code_lock"},
          {data,[{"Status",running},
                 {"Parent",<0.61.0>},
                 {"Logged Events",[]},
                 {"Postponed",[]}]},
          {data,[{"State",
                  {locked,#{code => [1,2,3,4],remaining => [1,2,3,4]}}}]}]]}
    

6.2 विशेष प्रक्रियाएँ

यह खंड एक मानक व्यवहार का उपयोग किए बिना, ओटीपी डिजाइन सिद्धांतों का अनुपालन करने वाली प्रक्रिया लिखने का वर्णन करता है। ऐसी प्रक्रिया है:

  • एक तरह से शुरू किया जाए जो प्रक्रिया को पर्यवेक्षण के पेड़ में फिट बनाता है
  • sys debug facilities समर्थन करें
  • system messages का ध्यान रखें।

सिस्टम संदेश एक विशेष अर्थ वाले संदेश हैं, जिसका उपयोग पर्यवेक्षण के पेड़ में किया जाता है। विशिष्ट सिस्टम संदेश ट्रेस आउटपुट के लिए अनुरोध हैं, और प्रक्रिया निष्पादन को निलंबित करने या फिर से शुरू करने के लिए अनुरोध (रिलीज हैंडलिंग के दौरान उपयोग किया जाता है)। मानक व्यवहारों का उपयोग करके लागू की गई प्रक्रियाएं इन संदेशों को स्वचालित रूप से समझती हैं।

उदाहरण

Overview से सरल सर्वर, sys और proc_lib का उपयोग करके कार्यान्वित किया गया ताकि यह एक पर्यवेक्षण वृक्ष में फिट हो जाए:

-module(ch4).
-export([start_link/0]).
-export([alloc/0, free/1]).
-export([init/1]).
-export([system_continue/3, system_terminate/4,
         write_debug/3,
         system_get_state/1, system_replace_state/2]).

start_link() ->
    proc_lib:start_link(ch4, init, [self()]).

alloc() ->
    ch4 ! {self(), alloc},
    receive
        {ch4, Res} ->
            Res
    end.

free(Ch) ->
    ch4 ! {free, Ch},
    ok.

init(Parent) ->
    register(ch4, self()),
    Chs = channels(),
    Deb = sys:debug_options([]),
    proc_lib:init_ack(Parent, {ok, self()}),
    loop(Chs, Parent, Deb).

loop(Chs, Parent, Deb) ->
    receive
        {From, alloc} ->
            Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3,
                                    ch4, {in, alloc, From}),
            {Ch, Chs2} = alloc(Chs),
            From ! {ch4, Ch},
            Deb3 = sys:handle_debug(Deb2, fun ch4:write_debug/3,
                                    ch4, {out, {ch4, Ch}, From}),
            loop(Chs2, Parent, Deb3);
        {free, Ch} ->
            Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3,
                                    ch4, {in, {free, Ch}}),
            Chs2 = free(Ch, Chs),
            loop(Chs2, Parent, Deb2);

        {system, From, Request} ->
            sys:handle_system_msg(Request, From, Parent,
                                  ch4, Deb, Chs)
    end.

system_continue(Parent, Deb, Chs) ->
    loop(Chs, Parent, Deb).

system_terminate(Reason, _Parent, _Deb, _Chs) ->
    exit(Reason).

system_get_state(Chs) ->
    {ok, Chs}.

system_replace_state(StateFun, Chs) ->
    NChs = StateFun(Chs),
    {ok, NChs, NChs}.

write_debug(Dev, Event, Name) ->
    io:format(Dev, "~p event = ~p~n", [Name, Event]).

उदाहरण के लिए कैसे sys मॉड्यूल में साधारण डीबगिंग फ़ंक्शन का उपयोग ch4 लिए भी किया जा सकता है:

% erl
Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]

Eshell V5.2.3.6  (abort with ^G)
1> ch4:start_link().
{ok,<0.30.0>}
2> sys:statistics(ch4, true).
ok
3> sys:trace(ch4, true).
ok
4> ch4:alloc().
ch4 event = {in,alloc,<0.25.0>}
ch4 event = {out,{ch4,ch1},<0.25.0>}
ch1
5> ch4:free(ch1).
ch4 event = {in,{free,ch1}}
ok
6> sys:statistics(ch4, get).
{ok,[{start_time,{{2003,6,13},{9,47,5}}},
     {current_time,{{2003,6,13},{9,47,56}}},
     {reductions,109},
     {messages_in,2},
     {messages_out,1}]}
7> sys:statistics(ch4, false).
ok
8> sys:trace(ch4, false).
ok
9> sys:get_status(ch4).
{status,<0.30.0>,
        {module,ch4},
        [[{'$ancestors',[<0.25.0>]},{'$initial_call',{ch4,init,[<0.25.0>]}}],
         running,<0.25.0>,[],
         [ch1,ch2,ch3]]}

प्रक्रिया शुरू करना

प्रक्रिया शुरू करने के लिए proc_lib मॉड्यूल में एक फ़ंक्शन का उपयोग किया जाना है। कई कार्य उपलब्ध हैं, उदाहरण के लिए, अतुल्यकालिक शुरुआत के लिए spawn_link/3,4 और सिंक्रोनस प्रारंभ के लिए start_link/3,4,5

इन कार्यों में से एक का उपयोग करके एक प्रक्रिया शुरू हो गई है, जो जानकारी (उदाहरण के लिए, पूर्वजों और प्रारंभिक कॉल के बारे में) को संग्रहीत करती है जो एक पर्यवेक्षण के पेड़ में एक प्रक्रिया के लिए आवश्यक है।

यदि प्रक्रिया normal या shutdown होने के अलावा किसी अन्य कारण से समाप्त हो जाती है, तो क्रैश रिपोर्ट उत्पन्न होती है। क्रैश रिपोर्ट के बारे में अधिक जानकारी के लिए, एसएएसएल उपयोगकर्ता गाइड देखें।

उदाहरण में, सिंक्रोनस स्टार्ट का उपयोग किया जाता है। प्रक्रिया ch4:start_link() को कॉल करके शुरू होती है:

start_link() ->
    proc_lib:start_link(ch4, init, [self()]).

ch4:start_link फ़ंक्शन को कॉल करता है proc_lib:start_link । यह फ़ंक्शन एक मॉड्यूल नाम, एक फ़ंक्शन नाम और एक तर्क सूची को तर्क, स्पॉन और एक नई प्रक्रिया के लिंक के रूप में लेता है। नई प्रक्रिया दी गई फ़ंक्शन को निष्पादित करने से शुरू होती है, यहां ch4:init(Pid) , जहां Pid पहली प्रक्रिया का pid ( self() है, जो कि मूल प्रक्रिया है।

नाम पंजीकरण सहित सभी आरंभीकरण, init में किया जाता है। नई प्रक्रिया को यह भी स्वीकार करना होगा कि इसे अभिभावक के लिए शुरू किया गया है:

init(Parent) ->
    ...
    proc_lib:init_ack(Parent, {ok, self()}),
    loop(...).

proc_lib:start_link सिंक्रोनस है और जब तक proc_lib:init_ack नहीं proc_lib:init_ack कहा जाता है।

डिबगिंग

sys में डिबग सुविधाकर्ताओं का समर्थन करने के लिए, डिबग संरचना की आवश्यकता है। Deb शब्द का उपयोग sys:debug_options/1 का उपयोग करके किया जाता है sys:debug_options/1 :

init(Parent) ->
    ...
    Deb = sys:debug_options([]),
    ...
    loop(Chs, Parent, Deb).

sys:debug_options/1 तर्क के रूप में विकल्पों की एक सूची लेता है। यहां सूची रिक्त है, जिसका अर्थ है कि कोई डीबगिंग प्रारंभ में सक्षम नहीं है। संभावित विकल्पों के बारे में जानकारी के लिए, STDLIB में sys(3) मैनुअल पेज देखें।

फिर, प्रत्येक सिस्टम ईवेंट को लॉग या ट्रेस करने के लिए, निम्न फ़ंक्शन को कॉल करना है।

sys:handle_debug(Deb, Func, Info, Event) => Deb1

यहाँ:

  • Deb डिबग संरचना है।
  • Func एक मजेदार (उपयोगकर्ता-परिभाषित) फ़ंक्शन को निर्दिष्ट करता है जो ट्रेस आउटपुट को प्रारूपित करने के लिए उपयोग किया जाता है। प्रत्येक सिस्टम ईवेंट के लिए, प्रारूप फ़ंक्शन को Func(Dev, Event, Info) कहा जाता है, जहां:
    • Dev I / O डिवाइस है जिसके लिए आउटपुट प्रिंट करना है। STDLIB में io(3) मैनुअल पेज देखें।
    • Event और Info पास की गई है जैसे कि handle_debug
  • Func को अधिक जानकारी देने के लिए Info का उपयोग किया जाता है। यह कोई भी शब्द हो सकता है और जैसा है वैसे ही पारित किया जाता है।
  • Event सिस्टम ईवेंट है। यह उपयोगकर्ता पर निर्भर है कि सिस्टम ईवेंट क्या है और इसका प्रतिनिधित्व कैसे किया जाए। आमतौर पर कम से कम इनकमिंग और आउटगोइंग संदेशों को सिस्टम इवेंट माना जाता है और क्रमशः tuples {in,Msg[,From]} और {out,Msg,To[,State]} दर्शाया जाता है।

handle_debug एक अद्यतन डीबग संरचना Deb1

उदाहरण में, प्रत्येक आवक और जावक संदेश के लिए handle_debug को कॉल किया जाता है। फंक्शन फंक्शन ch4:write_debug/3 फंक्शन ch4:write_debug/3 , जो io:format/3 का उपयोग करके संदेश को प्रिंट करता है।

loop(Chs, Parent, Deb) ->
    receive
        {From, alloc} ->
            Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3,
                                    ch4, {in, alloc, From}),
            {Ch, Chs2} = alloc(Chs),
            From ! {ch4, Ch},
            Deb3 = sys:handle_debug(Deb2, fun ch4:write_debug/3,
                                    ch4, {out, {ch4, Ch}, From}),
            loop(Chs2, Parent, Deb3);
        {free, Ch} ->
            Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3,
                                    ch4, {in, {free, Ch}}),
            Chs2 = free(Ch, Chs),
            loop(Chs2, Parent, Deb2);
        ...
    end.

write_debug(Dev, Event, Name) ->
    io:format(Dev, "~p event = ~p~n", [Name, Event]).

सिस्टम संदेश संभालना

सिस्टम संदेश इस प्रकार प्राप्त होते हैं:

{system, From, Request}

इन संदेशों की सामग्री और अर्थ को प्रक्रिया द्वारा व्याख्या करने की आवश्यकता नहीं है। इसके बजाय निम्नलिखित फ़ंक्शन को बुलाया जाना है:

sys:handle_system_msg(Request, From, Parent, Module, Deb, State)

यह फ़ंक्शन वापस नहीं आता है। यह सिस्टम संदेश को संभालता है और फिर प्रक्रिया को जारी रखने के लिए निम्नलिखित को कॉल करता है:

Module:system_continue(Parent, Deb, State)

या प्रक्रिया को समाप्त करने के लिए निम्नलिखित को कॉल करता है:

Module:system_terminate(Reason, Parent, Deb, State)

एक पर्यवेक्षण पेड़ में एक प्रक्रिया को इसके माता-पिता के समान कारण से समाप्त करने की उम्मीद की जाती है।

  • Request एंड From पास किया जाना है जैसा कि सिस्टम मैसेज से कॉल टू handle_system_msg
  • Parent के पिता हैं।
  • Module का नाम है।
  • Deb डिबग संरचना है।
  • State आंतरिक अवस्था का वर्णन करने वाला शब्द है और इसे system_continue / system_terminate / system_get_state / system_replace_state

यदि प्रक्रिया अपने राज्य को वापस करना है, तो handle_system_msg कॉल करें:

Module:system_get_state(State)

यदि यह प्रक्रिया अपने राज्य को मजेदार StateFun का उपयोग करके प्रतिस्थापित StateFun , तो handle_system_msg कॉल करें:

Module:system_replace_state(StateFun, State)

उदाहरण में:

loop(Chs, Parent, Deb) ->
    receive
        ...

        {system, From, Request} ->
            sys:handle_system_msg(Request, From, Parent,
                                  ch4, Deb, Chs)
    end.

system_continue(Parent, Deb, Chs) ->
    loop(Chs, Parent, Deb).

system_terminate(Reason, Parent, Deb, Chs) ->
    exit(Reason).

system_get_state(Chs) ->
    {ok, Chs, Chs}.

system_replace_state(StateFun, Chs) ->
    NChs = StateFun(Chs),
    {ok, NChs, NChs}.

यदि विशेष प्रक्रिया को बाहर निकालने के लिए निर्धारित किया जाता है और यदि मूल प्रक्रिया समाप्त हो जाती है, तो अपेक्षित व्यवहार उसी कारण से समाप्त होता है:

init(...) ->
    ...,
    process_flag(trap_exit, true),
    ...,
    loop(...).

loop(...) ->
    receive
        ...

        {'EXIT', Parent, Reason} ->
            ..maybe some cleaning up here..
            exit(Reason);
        ...
    end.

6.3 उपयोगकर्ता-परिभाषित व्यवहार

उपयोगकर्ता-परिभाषित व्यवहार को लागू करने के लिए, एक विशेष प्रक्रिया के लिए कोड के समान कोड लिखें, लेकिन विशिष्ट कार्यों को संभालने के लिए कॉलबैक मॉड्यूल में कॉल फ़ंक्शन।

यदि कंपाइलर गुम कॉलबैक फ़ंक्शंस के लिए चेतावनी देता है, जैसा कि ओटीपी व्यवहारों के लिए होता है, तो अपेक्षित कॉलबैक का वर्णन करने के लिए व्यवहार मॉड्यूल में एड- -callback विशेषताएँ:

-callback Name1(Arg1_1, Arg1_2, ..., Arg1_N1) -> Res1.
-callback Name2(Arg2_1, Arg2_2, ..., Arg2_N2) -> Res2.
...
-callback NameM(ArgM_1, ArgM_2, ..., ArgM_NM) -> ResM.

NameX अपेक्षित कॉलबैक के नाम हैं। ArgX_Y और ResX प्रकार हैं जैसा कि वे Types and Function Specifications में वर्णित हैं। -spec विशेषता का पूरा सिंटैक्स -spec विशेषता द्वारा समर्थित है।

कॉलबैक फ़ंक्शन जो कार्यान्वित करने के लिए व्यवहार के उपयोगकर्ता के लिए वैकल्पिक हैं, उन्हें -optional_callbacks विशेषता के उपयोग द्वारा निर्दिष्ट किया जाता है:

-optional_callbacks([OptName1/OptArity1, ..., OptNameK/OptArityK]).

जहाँ प्रत्येक OptName/OptArity एक कॉलबैक फ़ंक्शन का नाम और OptName/OptArity निर्दिष्ट करता है। ध्यान दें कि -callback विशेषता को -callback विशेषता के साथ उपयोग किया -callback है; इसे नीचे दिए गए behaviour_info() फ़ंक्शन के साथ जोड़ा नहीं जा सकता।

वैकल्पिक कॉलबैक फ़ंक्शंस के बारे में जानने के लिए जिन टूल की आवश्यकता होती है, वे सभी वैकल्पिक कॉलबैक फ़ंक्शंस की सूची प्राप्त करने के लिए Behaviour:behaviour_info(optional_callbacks) वैकल्पिक_ कॉलबैक Behaviour:behaviour_info(optional_callbacks) को कॉल कर सकते हैं।

ध्यान दें

हम behaviour_info() -callback behaviour_info() फ़ंक्शन के बजाय -callback विशेषता का उपयोग करने की सलाह देते हैं। कारण यह है कि अतिरिक्त प्रकार की जानकारी का उपयोग दस्तावेजों के उत्पादन के लिए किया जा सकता है या विसंगतियों का पता लगा सकते हैं।

-callback और -callback विशेषताओं के विकल्प के रूप में आप behaviour_info() को सीधे कार्यान्वित और निर्यात कर सकते हैं -callback behaviour_info() :

behaviour_info(callbacks) ->
    [{Name1, Arity1},...,{NameN, ArityN}].

जहाँ प्रत्येक {Name, Arity} एक कॉलबैक फ़ंक्शन का नाम और {Name, Arity} निर्दिष्ट करता है। यह फ़ंक्शन अन्यथा संकलक द्वारा -callback विशेषताओं का उपयोग करके स्वचालित रूप से उत्पन्न होता है।

जब कंपाइलर मॉड्यूल विशेषता -behaviour(Behaviour). सामना करता है -behaviour(Behaviour). एक मॉड्यूल Mod , यह Behaviour:behaviour_info(callbacks) कहता है Behaviour:behaviour_info(callbacks) और परिणाम की तुलना वास्तव में Mod से निर्यात किए गए फ़ंक्शंस के सेट के साथ करता है, और यदि कोई कॉलबैक फ़ंक्शन गायब है तो चेतावनी जारी करता है।

उदाहरण:

%% User-defined behaviour module
-module(simple_server).
-export([start_link/2, init/3, ...]).

-callback init(State :: term()) -> 'ok'.
-callback handle_req(Req :: term(), State :: term()) -> {'ok', Reply :: term()}.
-callback terminate() -> 'ok'.
-callback format_state(State :: term()) -> term().

-optional_callbacks([format_state/1]).

%% Alternatively you may define:
%%
%% -export([behaviour_info/1]).
%% behaviour_info(callbacks) ->
%%     [{init,1},
%%      {handle_req,2},
%%      {terminate,0}].

start_link(Name, Module) ->
    proc_lib:start_link(?MODULE, init, [self(), Name, Module]).

init(Parent, Name, Module) ->
    register(Name, self()),
    ...,
    Dbg = sys:debug_options([]),
    proc_lib:init_ack(Parent, {ok, self()}),
    loop(Parent, Module, Deb, ...).

...

कॉलबैक मॉड्यूल में:

-module(db).
-behaviour(simple_server).

-export([init/1, handle_req/2, terminate/0]).

...

व्यवहार मॉड्यूल में -callback विशेषताओं के साथ निर्दिष्ट अनुबंध कॉलबैक मॉड्यूल में -spec विशेषताओं को जोड़कर और अधिक परिष्कृत किया जा सकता है। यह उपयोगी हो सकता है क्योंकि -callback कॉन्ट्रैक्ट आमतौर पर सामान्य होते हैं। कॉलबैक के अनुबंध के साथ समान कॉलबैक मॉड्यूल:

-module(db).
-behaviour(simple_server).

-export([init/1, handle_req/2, terminate/0]).

-record(state, {field1 :: [atom()], field2 :: integer()}).

-type state()   :: #state{}.
-type request() :: {'store', term(), term()};
                   {'lookup', term()}.

...

-spec handle_req(request(), state()) -> {'ok', term()}.

...

प्रत्येक -spec अनुबंध संबंधित -callback अनुबंध का उपप्रकार होना है।