2009-08-09 13 views
110

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

हालांकि, मैं Programming in Scala में स्कैला के अभिनेता ढांचे के बारे में पढ़ रहा हूं, और एक बात है जिसे मैं समझ नहीं पा रहा हूं। अध्याय 30.4 में यह कहता है कि के बजाय का उपयोग करके थ्रेड का पुन: उपयोग करना संभव हो जाता है, जो प्रदर्शन के लिए अच्छा है, चूंकि धागे JVM में महंगी हैं।

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

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

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

loop { 
    react { 
     ... 
    } 
} 

मेरे लिए बहुत

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

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

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

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

+2

यह भी देखें http://stackoverflow.com/questions/1526845/when-are-threads-created-for-scala-actors –

उत्तर

77

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

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

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

20

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

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

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

19

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

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

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

जावा अभिनेता ढांचा Kilim वास्तव में स्टैक रखरखाव करता है जो एक संदेश प्राप्त करने पर प्रतिक्रिया को अनलॉक कर देता है।

+0

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

+0

ग्रेट उत्तर। मुझे वह नहीं मिला है। – santiagobasulto

8

बस इसे यहां के लिए:

Event-Based Programming without Inversion of Control

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

+0

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

0

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

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

संबंधित मुद्दे