0 प्रस्तावना
सुखद रूप से सहमत हों, जब घर में सब कुछ नियंत्रण में है और सब कुछ क्रम में है, तो प्रत्येक वस्तु अपनी जगह पर खड़ी है और स्पष्ट रूप से अपने सार्वभौमिक उद्देश्य को पूरा करती है। आज हम एक विशाल विविधता की प्रक्रिया में व्यवस्था के संगठन पर विचार करेंगे। Erlang प्रक्रियाओं के बारे में बुनियादी अवधारणाएं इस
पोस्ट में पाई जा सकती हैं।
1 आप मेरा अनुसरण करते हैं - मैं आपका अनुसरण करता हूं
हर कोई जो एर्गैंग से परिचित था एक तरह से या किसी अन्य ने वाक्यांश सुना: "प्रक्रिया को गिरने दें, और दूसरा इसके बारे में कुछ करेगा या समस्या से निपटेगा।" सहमत हों, जब कुछ टूटता है, तो यह बुरा है, लेकिन अगर हम लंबे समय तक इसके बारे में नहीं जानते हैं, तो यह दोगुना बुरा है। आपकी बिल्ली ने उसके दूध का कटोरा तोड़ दिया और इस भयानक तथ्य को आपसे छिपा दिया - बुरा! कटोरा बिल्ली का पालन करें, और बिल्ली कटोरा। इस तरह की क्रूड तुलना के लिए लेखक के पाठकों को क्षमा करें। तो, चलो व्यापार के लिए नीचे उतरो।
एक दूसरे की स्थिति की निगरानी करने के लिए आपस में प्रक्रियाओं का जुड़ाव एरंग की मूल अवधारणाओं में से एक है। एक जटिल और अच्छी तरह से डिज़ाइन की गई प्रणाली में, कोई भी प्रक्रिया "हवा में लटका" नहीं होनी चाहिए। सभी प्रक्रियाओं को नियंत्रण पेड़ में एम्बेड किया जाना चाहिए, जिनमें से पत्तियां काम की प्रक्रियाएं हैं, और आंतरिक नोड्स श्रमिकों (नियंत्रक) की निगरानी करते हैं [2] ओटीपी (ओपन टेलीकॉम प्लेटफ़ॉर्म)] के सिद्धांत। यद्यपि यह किया जा सकता है ताकि दोनों कार्यकर्ता जुड़े रहें।

चित्र 1
यदि आप ओटीपी प्रदान करने वाले एब्स्ट्रैक्शन के स्तर तक नहीं बढ़ते हैं, तो एरलंग में कनेक्टिंग प्रक्रियाओं के लिए दो तंत्र हैं:
- लिंक - दो प्रक्रियाओं के बीच एक द्विदिश लिंक।
- मॉनिटर एक पर्यवेक्षक प्रक्रिया और एक अवलोकन के बीच एक-तरफ़ा कनेक्शन है।
1.1 संबंध
प्रक्रियाओं के बीच संबंध बनाने के लिए निम्नलिखित कार्यों का उपयोग किया जाता है:
- erlang: लिंक / 1 - कॉलिंग फ़ंक्शन और एक अन्य प्रक्रिया के बीच संबंध बनाना;
- erlang: spawn_link / 1/2/3/4 (इसमें अन्य उपनाम भी है_lib: spawn_link / 1/2/3/4) - एक नई प्रक्रिया बनाएं और फ़ंक्शन को कॉल करने वाली प्रक्रिया से लिंक करें;
- एर्लांग: अनलिंक / 1 - फ़ंक्शन को कॉल करने वाली प्रक्रिया और तर्कों में निर्दिष्ट एक के बीच के कनेक्शन को हटा देता है;
- पूल: pspawn_link / 3 - पूल में एक नोड पर एक नई प्रक्रिया बनाते हैं और इसे उस प्रक्रिया से जोड़ते हैं जो फ़ंक्शन को कॉल करता है।
प्रक्रियाओं के बीच हमें द्विदिश संचार क्या देता है? रिश्ते यह निर्धारित करते हैं कि त्रुटियाँ कैसे फैलती हैं। एक प्रक्रिया की मृत्यु हो गई, दूसरे ने इसके बारे में सीखा और कई मामलों में, जिन पर हम नीचे विचार करेंगे, यह अपना काम भी पूरा करेगा, अन्य सभी प्रक्रियाओं के लिए एक संकेत भेजेगा जो इसके साथ संलग्न हैं। यह तंत्र आपको त्रुटियों को दूर करने की अनुमति देता है, अर्थात। हैंडलर एक अलग प्रक्रिया (नियंत्रक) हो सकती है, जिसके लिए ये सभी त्रुटियां लिंक के माध्यम से "प्रवाह" करेंगी, और हैंडलर प्रक्रिया पूरी तरह से दूसरे नोड पर स्थित हो सकती है। और ये सभी उपहार लगभग मुफ्त हैं - सब कुछ पहले से ही प्लेटफॉर्म में लागू किया गया है, हमें बस अपनी मेगा-सुपर-फेल-वितरित प्रणाली का सही ढंग से निर्माण करना है।

चित्र 2
जब प्रक्रिया क्रैश हो जाती है (चित्र 2 देखें), एक आउटपुट सिग्नल सभी लिंक की गई प्रक्रियाओं को भेजा जाता है, इस सिग्नल में जानकारी होती है कि किस प्रक्रिया और किस कारण से युद्ध में मृत्यु हुई। संकेत एक टपल {'बाहर', पिद, कारण} है।
कारण चर के लिए दो पूर्वनिर्धारित मूल्य हैं:
- सामान्य - कारण का यह मान सेट किया जाता है यदि प्रक्रिया ने वह सभी काम पूरा कर लिया है जिसे हमने इसे लोड किया था, अर्थात। बस उस फ़ंक्शन के अंत तक पहुंच गया जिसके साथ इसे बुलाया गया था। इस मामले में, जो प्रक्रियाएँ इससे जुड़ी हैं, वे अपना काम पूरा नहीं करेंगी।
- मार - एक गैर-अवरोधक संकेत जो हमेशा एक प्रक्रिया को मारता है, यहां तक कि एक सिस्टम एक, का उपयोग विफल प्रक्रियाओं को समाप्त करने के लिए किया जाता है।
आउटपुट सिग्नल को इंटरसेप्ट करने में सक्षम होने की प्रक्रिया के लिए, इसे tra__exit फ़्लैग को process_flag फंक्शन (trap_exit, true) पर कॉल करके सिस्टम बनाया जाना चाहिए।
तो, पर्याप्त सिद्धांत, चलो व्यवहार में सब कुछ करने की कोशिश करते हैं। हमारा पसंदीदा संपादक खोलें और एक छोटा मॉड्यूल बनाएं। आइए पहले प्रक्रिया की सामान्य समाप्ति का परीक्षण करें। प्रयोग की सादगी के लिए, हमारे पास प्रक्रियाओं में से एक के रूप में एक शेल होगा।
-module(links_test). -export([start_n/1, loop_n/1]). start_n(Sysproc) -> %% test normal reason process_flag(trap_exit, Sysproc), io:format("Shell Pid: ~p~n", [self()]), Pid = spawn_link(links_test, loop_n, [self()]), io:format("Process started with Pid: ~p~n", [Pid]). loop_n(Shell) -> %% loop for test normal reason receive after 5000 -> Shell ! timeout end.
मॉड्यूल में दो फ़ंक्शन परिभाषित होते हैं: पहला start_n एक नई प्रक्रिया बनाता है और इसे कॉलिंग प्रक्रिया से जोड़ता है (हमारे मामले में यह एक शेल होगा), यह पैरामीटर के रूप में मूल्य बूलियन लेता है, जो सिस्टम को सिस्टम बनाता है। दूसरा लूप_ एन बनाई जा रही प्रक्रिया का निकाय है, एक तर्क के रूप में हम इसे कॉलिंग प्रक्रिया (शेल) से मुक्त करते हैं। प्रक्रिया शुरू होने के 5 सेकंड बाद, यह शेल को एक टाइमआउट संदेश भेजता है। हम अपनी प्रक्रिया को संकलित करते हैं और चलाते हैं।
(emacs@aleksio-mobile)2> links_test:start_n(false). Shell Pid: <0.36.0> Process started with Pid: <0.43.0> ok (emacs@aleksio-mobile)3> flush(). Shell got timeout ok (emacs@aleksio-mobile)4>
हम गलत पैरामीटर के साथ links_test: start_n फ़ंक्शन को कॉल करते हैं, अर्थात शेल एक सिस्टम प्रक्रिया नहीं है और आउटपुट सिग्नल नहीं पकड़ सकता है। हम देखते हैं कि प्रक्रिया सफलतापूर्वक बनाई गई थी, क्योंकि लूप_ एन फ़ंक्शन में कोई पूंछ पुनरावृत्ति नहीं है, यह सफलतापूर्वक निष्पादित होगा और प्रक्रिया समाप्त हो जाएगी। हम शेल मेलबॉक्स से सभी संदेशों को छोड़ने के लिए फ्लश () फ़ंक्शन को कॉल करते हैं, और हम देखते हैं कि हमारी प्रक्रिया "शेल टाइमआउट" से एक संदेश प्राप्त हुआ था। हम कोई आउटपुट सिग्नल नहीं देखते हैं, क्योंकि इस प्रकार के सिग्नल को संसाधित करने के लिए ध्वज सेट नहीं किया गया है। अब शेल को एक सिस्टम प्रक्रिया बनाएं।
(emacs@aleksio-mobile)5> links_test:start_n(true). Shell Pid: <0.36.0> Process started with Pid: <0.51.0> ok (emacs@aleksio-mobile)6> flush(). Shell got timeout Shell got {'EXIT',<0.51.0>,normal} ok (emacs@aleksio-mobile)8>
फ़ंक्शन को निष्पादित करने के बाद, हम देखते हैं कि टाइमआउट संदेश के अलावा, हमारी प्रक्रिया {'EXIT', <0.51.0>, सामान्य} से सामान्य समाप्ति के बारे में एक संदेश प्राप्त हुआ था। एक अद्भुत तंत्र हमें कोड की मात्रा पर बचत करने की अनुमति देता है जब यह पता लगाना आवश्यक होता है कि प्रक्रिया ने अपना काम पूरा कर लिया है (सिग्नल भेजने की कोई आवश्यकता नहीं है "मैंने सब कुछ खुद किया")।
अब एक गैर-सामान्य त्रुटि उत्पन्न करने का प्रयास करते हैं। नीचे दी गई लिस्टिंग में मॉड्यूल कोड को संशोधित करें।
-module(links_test). -export([start_n/1, loop_n/1]). start_n(Sysproc) -> %% test abnormal reason process_flag(trap_exit, Sysproc), io:format("Shell Pid: ~p~n", [self()]), Pid = spawn_link(links_test, loop_n, [self()]), io:format("Process started with Pid: ~p~n", [Pid]). loop_n(Shell) -> %% loop for test abnormal reason receive after 5000 -> Shell ! timeout, 1 / 0 end.
हम बहुत गंभीर हैं और शून्य से विभाजित करने का फैसला किया है, संकलक स्वाभाविक रूप से हमें चेतावनी देगा कि हम गलत हैं, लेकिन हम बस उसकी चेतावनी को अनदेखा करेंगे।
(emacs@aleksio-mobile)33> links_test:start_n(false). Shell Pid: <0.117.0> Process started with Pid: <0.120.0> ok (emacs@aleksio-mobile)34> ** exception error: bad argument in an arithmetic expression in function links_test:loop_n/1 (emacs@aleksio-mobile)34> =ERROR REPORT==== 25-Feb-2011::16:22:48 === Error in process <0.120.0> on node 'emacs@aleksio-mobile' with exit value: {badarith,[{links_test,loop_n,1}]} (emacs@aleksio-mobile)34> flush(). ok (emacs@aleksio-mobile)35> self(). <0.122.0> (emacs@aleksio-mobile)36>
नोट शेल पीड = <0.117.0>। 5 सेकंड के बाद, एक त्रुटि यह बताते हुए निकल जाती है कि आखिर हम गलत थे। आइए यह देखने की कोशिश करें कि शेल की कतार में क्या है, और वहां यह खाली है। हमारा टाइमआउट पत्र कहां है? आइए स्वयं को निष्पादित करें () कमांड, शेल पीआईडी अब <0.122.0> के बराबर है - इसका मतलब है कि हमारी असफल प्रक्रिया ने कारण {badarith, [{links_test, loop_n, 1}]} के साथ एक शेल निकास संकेत भेजा, और इस उदाहरण में शेल के बाद से सिस्टम प्रक्रिया नहीं, यह सुरक्षित रूप से दुर्घटनाग्रस्त हो गया और किसी प्रकार के नियंत्रक द्वारा पुनः आरंभ किया गया था (जिसे हम भविष्य के लेखों में चर्चा करेंगे)। अब आउटपुट सिग्नल प्रोसेसिंग फ्लैग को सक्षम करें।
(emacs@aleksio-mobile)40> links_test:start_n(true). Shell Pid: <0.132.0> Process started with Pid: <0.139.0> ok (emacs@aleksio-mobile)41> =ERROR REPORT==== 25-Feb-2011::16:34:19 === Error in process <0.139.0> on node 'emacs@aleksio-mobile' with exit value: {badarith,[{links_test,loop_n,1}]} (emacs@aleksio-mobile)41> flush(). Shell got timeout Shell got {'EXIT',<0.139.0>,{badarith,[{links_test,loop_n,1}]}} ok (emacs@aleksio-mobile)42> self(). <0.132.0> (emacs@aleksio-mobile)43>
मुझे लगता है कि परिणामों पर टिप्पणी अनावश्यक है, यहां सब कुछ स्पष्ट है।
हमने चार मामलों की जांच की:
संकेत trap_exit | प्रक्रिया पूरी करने का कारण | प्रक्रिया की कार्रवाई जो "जीवित" बनी रही |
---|
सच | साधारण | मेलबॉक्स में {'EXIT', Pid, सामान्य} संदेश आता है |
झूठा | साधारण | प्रक्रिया अपना काम जारी रखती है |
सच | सामान्य और मारने के अलावा कोई और | मेलबॉक्स में {'EXIT', Pid, कारण} संदेश आता है |
झूठा | सामान्य और मारने के अलावा कोई और | प्रक्रिया मर जाती है, अपने सभी कनेक्शनों के लिए एक निकास संकेत भेजती है (यानी, त्रुटि प्रसार होता है) |
निष्कर्ष
निम्नलिखित लेखों में (
भाग 2 ,
भाग 3 ) हम मॉनिटर के तंत्र और किल संकेतों के साथ प्रक्रियाओं पर शूट करने पर विचार करेंगे। मैं हब्रोज़िटेल की राय सुनना चाहूंगा, उन लेखों पर जिन विषयों पर आप सबसे दिलचस्प होंगे?
संदर्भ
1.
उत्कृष्ट ऑनलाइन प्रलेखन ।
2.
ओटीपी के सिद्धांत ।
3. फ्रांसेस्को सेसरिनी और साइमन थॉम्पसन द्वारा ERLANG प्रोग्रामिंग।
4. प्रोग्रामिंग एरलांग: जो आर्मस्ट्रांग द्वारा एक समवर्ती दुनिया के लिए सॉफ्टवेयर।