स्काला अभिनेताओं: बनाम प्रतिक्रिया प्राप्त करते हैं


110

मुझे पहले बताएं कि मुझे जावा का काफी अनुभव है, लेकिन अभी हाल ही में कार्यात्मक भाषाओं में दिलचस्पी हुई है। हाल ही में मैंने स्काला को देखना शुरू किया है, जो बहुत अच्छी भाषा की तरह लगती है।

हालाँकि, मैं स्कैला में प्रोग्रामिंग में स्काला के अभिनेता ढांचे के बारे में पढ़ रहा हूं , और एक बात है जो मुझे समझ नहीं आ रही है। अध्याय 30.4 में यह है कि का उपयोग कर कहते हैं reactके बजाय receiveबनाता है यह फिर से उपयोग धागे, जो प्रदर्शन के लिए अच्छा है, क्योंकि सूत्र JVM में महंगे हैं करने के लिए संभव।

क्या इसका मतलब यह है कि जब तक मुझे reactइसके बजाय कॉल करने की याद है receive, मैं जितने चाहे उतने अभिनेता शुरू कर सकता हूं? स्काला की खोज करने से पहले, मैं एरलांग के साथ खेल रहा हूं, और प्रोग्रामिंग एरलांग के लेखक ने बिना पसीने के 200,000 से अधिक प्रक्रियाओं के बारे में बताया है। मैं जावा धागे के साथ ऐसा करने से नफरत करता हूँ। एरलांग (और जावा) की तुलना में स्काला में मैं किस तरह की सीमाएं देख रहा हूं?

इसके अलावा, यह धागा स्कैला में फिर से कैसे काम करता है? चलो मान लेते हैं, सादगी के लिए, कि मेरे पास केवल एक धागा है। क्या सभी कलाकार जो मैं इस धागे में क्रमिक रूप से चलना शुरू कर दूंगा, या किसी प्रकार का कार्य-स्विचन होगा? उदाहरण के लिए, यदि मैं दो अभिनेताओं को पिंग-पोंग संदेश देता हूं जो एक-दूसरे को संदेश देते हैं, तो क्या मैं एक ही धागे में शुरू होने पर गतिरोध का जोखिम उठाऊंगा?

स्काला में प्रोग्रामिंग के अनुसार , अभिनेताओं का उपयोग reactकरने की तुलना में लिखना अधिक कठिन है receive। यह प्रशंसनीय लगता है, क्योंकि reactवापस नहीं आता है। हालांकि, पुस्तक यह दिखाने के लिए जाती है कि आप reactएक लूप का उपयोग करके अंदर कैसे डाल सकते हैं Actor.loop। नतीजतन, आप प्राप्त करते हैं

loop {
    react {
        ...
    }
}

जो, मेरे लिए, के समान सुंदर लगता है

while (true) {
    receive {
        ...
    }
}

जिसका उपयोग पुस्तक में पहले किया गया है। फिर भी, पुस्तक कहती है कि "व्यवहार में, कार्यक्रमों को कम से कम कुछ receiveकी आवश्यकता होगी "। तो मैं यहाँ क्या याद कर रहा हूँ? वापसी के अलावा receiveवह क्या कर सकता है react? और मुझे क्यों परवाह है?

अंत में, जो मुझे समझ में नहीं आता है उसके मूल में आना: पुस्तक reactयह उल्लेख करती है कि थ्रेड को फिर से उपयोग करने के लिए कॉल स्टैक को त्यागना कैसे संभव है। वह कैसे काम करता है? कॉल स्टैक को त्यागना क्यों आवश्यक है? और जब फ़ंक्शन एक अपवाद ( react) को फेंककर समाप्त हो जाता है, तो कॉल स्टैक को क्यों खारिज किया जा सकता है , लेकिन जब यह वापस लौटने ( receive) द्वारा समाप्त नहीं होता है ?

मुझे आभास है कि स्काला में प्रोग्रामिंग यहाँ कुछ प्रमुख मुद्दों पर चमक रहा है, जो शर्म की बात है, क्योंकि अन्यथा यह वास्तव में एक उत्कृष्ट पुस्तक है।


जवाबों:


78

सबसे पहले, प्रत्येक अभिनेता जिस पर प्रतीक्षा कर रहा है, receiveवह एक थ्रेड पर कब्जा कर रहा है। यदि यह कभी कुछ प्राप्त नहीं करता है, तो वह धागा कभी भी कुछ नहीं करेगा। एक अभिनेता reactकिसी भी धागे पर तब तक कब्जा नहीं करता है जब तक कि वह कुछ प्राप्त नहीं करता है। एक बार जब यह कुछ प्राप्त करता है, तो एक धागा इसे आवंटित किया जाता है, और इसे इसमें आरंभ किया जाता है।

अब, प्रारंभिक भाग महत्वपूर्ण है। एक प्राप्त थ्रेड से कुछ वापस करने की अपेक्षा की जाती है, एक प्रतिक्रियाशील थ्रेड नहीं है। तो पिछले के अंत में पिछली स्टैक स्थिति reactहो सकती है, और पूरी तरह से खारिज कर दिया गया है। स्टैक स्थिति को बचाने या पुनर्स्थापित करने की आवश्यकता नहीं है, थ्रेड को प्रारंभ करने के लिए तेज़ बनाता है।

विभिन्न प्रदर्शन कारण हैं कि आप एक या दूसरे को क्यों चाहते हैं। जैसा कि आप जानते हैं, जावा में बहुत सारे धागे होना एक अच्छा विचार नहीं है। दूसरी ओर, क्योंकि आपको एक अभिनेता को एक धागे से जोड़ना होगा react, इससे पहले कि यह receiveसंदेश की तुलना में तेज़ reactहो। इसलिए यदि आपके पास ऐसे अभिनेता हैं जो कई संदेश प्राप्त करते हैं लेकिन इसके साथ बहुत कम करते हैं, तो अतिरिक्त देरी reactआपके उद्देश्यों के लिए इसे बहुत धीमा कर सकती है।


21

इसका उत्तर "हां" है - यदि आपके अभिनेता आपके कोड में किसी भी चीज पर रोक नहीं लगा रहे हैं और आप उपयोग कर रहे हैं react, तो आप अपने "समवर्ती" प्रोग्राम को एक ही धागे में चला सकते हैं (सिस्टम प्रॉपर्टी सेट करने का प्रयास करें)actors.maxPoolSize यह जानने के )।

अधिक स्पष्ट कारणों में से एक यह है कि कॉल स्टैक को त्यागना क्यों आवश्यक है, अन्यथा loopविधि ए में समाप्त हो जाएगी StackOverflowError। जैसा कि यह है, फ्रेमवर्क एक चतुराई से समाप्त होता है एक reactफेंकने से SuspendActorException, जो लूपिंग कोड द्वारा पकड़ा जाता है जो फिर से reactफिर से चलता हैandThen विधि के ।

में mkBodyविधि पर एक नज़र है Actorऔर फिर seqविधि देखने के लिए कैसे पाश खुद reschedules - बहुत चालाक सामान!


20

"स्टैक को त्यागना" के उन बयानों ने मुझे कुछ समय के लिए उलझन में डाल दिया और मुझे लगता है कि मैं इसे अभी प्राप्त करता हूं और यह अब मेरी समझ है। "प्राप्त" के मामले में, संदेश पर एक समर्पित थ्रेड अवरुद्ध होता है (ऑब्जेक्ट का उपयोग करके) (एक मॉनिटर पर) और इसका मतलब है कि पूरा थ्रेड स्टैक उपलब्ध है और एक प्राप्त करने पर "प्रतीक्षा" के बिंदु से जारी रखने के लिए तैयार है संदेश। उदाहरण के लिए यदि आपके पास निम्न कोड था

  def a = 10;
  while (! done)  {
     receive {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after receive and printing a " + a)
  }

जब तक संदेश प्राप्त नहीं होता है, तब थ्रेड प्राप्त कॉल में प्रतीक्षा करेगा और तब जारी रहेगा और "प्राप्त करने और प्रिंट करने के बाद 10" संदेश को प्रिंट करेगा और "10" के मूल्य के साथ जो कि थ्रेड ब्लॉक होने से पहले स्टैक फ्रेम में है।

प्रतिक्रिया के मामले में ऐसा कोई समर्पित धागा नहीं है, प्रतिक्रिया विधि की पूरी विधि को एक बंद के रूप में कैप्चर किया जाता है और एक संदेश प्राप्त करने वाले संबंधित अभिनेता पर कुछ मनमाने धागे द्वारा निष्पादित किया जाता है। इसका मतलब है कि केवल उन बयानों को जिन्हें अकेले बंद करने के रूप में पकड़ा जा सकता है, निष्पादित किया जाएगा और यही वह जगह है जहां "नथिंग" का रिटर्न प्रकार खेलना आता है। निम्नलिखित कोड पर विचार करें

  def a = 10;
  while (! done)  {
     react {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after react and printing a " + a) 
  }

यदि प्रतिक्रिया में शून्य प्रकार होता है, तो इसका मतलब होगा कि "प्रतिक्रिया" कॉल के बाद बयान होना कानूनी है (उदाहरण में प्रिंटलाइन स्टेटमेंट जो संदेश को प्रिंट करता है "प्रतिक्रिया और मुद्रण के बाद 10"), लेकिन वास्तविकता में कभी भी निष्पादित नहीं किया जाएगा क्योंकि केवल "प्रतिक्रिया" विधि के शरीर को पकड़ लिया जाता है और बाद में निष्पादन के लिए अनुक्रमित किया जाता है (एक संदेश के आने पर)। चूंकि प्रतिक्रिया के अनुबंध में "कुछ भी नहीं" का वापसी प्रकार है, इसलिए प्रतिक्रिया के बाद कोई भी बयान नहीं हो सकता है, और स्टैक बनाए रखने का कोई कारण नहीं है। चर के ऊपर के उदाहरण में "a" को बनाए रखना नहीं होगा क्योंकि प्रतिक्रियाओं के बाद कॉल को निष्पादित नहीं किया जाता है। ध्यान दें कि प्रतिक्रिया के शरीर द्वारा सभी आवश्यक चर को पहले से ही एक बंद के रूप में कब्जा कर लिया गया है, इसलिए यह बस ठीक निष्पादित कर सकता है।

जावा एक्टर फ्रेमवर्क किलीम वास्तव में स्टैक को सेव करके स्टैक मेंटेन करता है जो कि मैसेज मिलने वाले रिएक्शन पर अनियंत्रित हो जाता है।


धन्यवाद, यह बहुत जानकारीपूर्ण था। लेकिन क्या आपको +aकोड स्निपेट के बजाय इसका मतलब नहीं था +10?
जकोनो

बहुत बढ़िया जवाब। मुझे न तो ऐसा लगता है।
संटियागोबसुल्तो

8

बस यहाँ है:

घटना-आधारित प्रोग्रामिंग बिना नियंत्रण के उलटा

ये कागजात अभिनेता के लिए स्काला एप से जुड़े हैं और अभिनेता के कार्यान्वयन के लिए सैद्धांतिक ढांचा प्रदान करते हैं। इसमें यह शामिल है कि प्रतिक्रिया कभी वापस क्यों नहीं आ सकती।


और दूसरा पेपर। खराब स्पैम नियंत्रण ... :( [अभिनेता जो धागे और घटनाओं को एकजुट करते हैं] [2] [2]: lamp.epfl.ch/~phaller/doc/haller07coord.pdf "अभिनेता जो थ्रेड्स और इवेंट्स को एकजुट करते हैं"
हेक्सरेन

0

मैंने स्काला / एक्का के साथ कोई बड़ा काम नहीं किया है, हालांकि मैं समझता हूं कि अभिनेताओं के शेड्यूल करने के तरीके में बहुत महत्वपूर्ण अंतर है। अक्का सिर्फ एक स्मार्ट थ्रेडपूल है जो अभिनेताओं के निष्पादन का समय निर्धारित करता है ... हर बार स्लाइस एक एर्लैंग के विपरीत एक अभिनेता द्वारा पूरा करने के लिए एक संदेश निष्पादन होगा जो निर्देश के अनुसार हो सकता है ?!

यह मुझे सोचने के लिए प्रेरित करता है कि प्रतिक्रिया बेहतर है क्योंकि यह शेड्यूलिंग के लिए अन्य अभिनेताओं पर विचार करने के लिए वर्तमान थ्रेड को इंगित करता है जहां "प्राप्त" उसी एक्टर के लिए अन्य संदेशों को निष्पादित करने के लिए वर्तमान थ्रेड को "प्राप्त" कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.