2013-03-02 2 views
12

मैं सिर्फ एक परेशान व्यवहार देखा है लटका कारण बनता है। चलो कहते हैं कि मैं एक स्टैंडअलोन एक एकमात्र उद्देश्य से मिलकर कार्यक्रम है दो:स्काला: ऑब्जेक्ट प्रारंभकर्ता में समानांतर संग्रह एक कार्यक्रम

object ParCollectionInInitializerTest { 
    def doSomething { println("Doing something") } 

    for (i <- (1 to 2).par) { 
    println("Inside loop: " + i) 
    doSomething 
    } 

    def main(args: Array[String]) { 
    } 
} 

कार्यक्रम पूरी तरह से निर्दोष है और, जब पाश के लिए में इस्तेमाल सीमा नहीं एक समानांतर एक है, ठीक से निष्पादित करता है, तो निम्न उत्पादन के साथ :

पाश के अंदर: 1
कर कुछ
पाश के अंदर: 2
कुछ

कर

दुर्भाग्य से, जब समानांतर संग्रह का उपयोग करके, कार्यक्रम सिर्फ कभी DoSomething विधि लागू बिना लटकी हुई है, इसलिए उत्पादन इस प्रकार है:

पाश के अंदर: 2
पाश के अंदर: 1

और फिर कार्यक्रम लटका हुआ है।
यह सिर्फ एक बुरा बग है? मैं स्कैला-2.10 का उपयोग कर रहा हूँ।

+0

संबंधित: http: // stackoverflow।कॉम/प्रश्न/27549671/कैसे-से-निदान-या-पता-डेडलॉक्स-इन-जावा-स्थिर-प्रारंभिक – Rich

उत्तर

15

यह एक अंतर्निहित समस्या है जो निर्माण पूरा होने से पहले सिंगलटन ऑब्जेक्ट के संदर्भ को जारी करते समय स्कैला में हो सकती है। यह एक अलग धागे से पहले यह पूरी तरह से निर्माण किया गया है वस्तु ParCollectionInInitializerTest पहुंचने का प्रयास कर के कारण होता है। इसका main विधि से कोई लेना देना नहीं है, बल्कि इसे उस ऑब्जेक्ट को प्रारंभ करने के साथ करना है जिसमें main विधि शामिल है - इसे REPL में चलाने का प्रयास करें, ParCollectionInInitializerTest अभिव्यक्ति में टाइप करना और आपको वही परिणाम मिलेंगे। फोर्क-जॉइन वर्कर थ्रेड्स के साथ डिमन थ्रेड होने के साथ इसका कोई संबंध नहीं है।

सिंगलटन वस्तुओं lazily प्रारंभ कर रहे हैं। प्रत्येक सिंगलटन ऑब्जेक्ट को केवल एक बार शुरू किया जा सकता है। इसका मतलब है कि पहली बात यह है कि वस्तु तक पहुँचता है (अपने मामले, मुख्य थ्रेड में) वस्तु का एक ताला हड़पने चाहिए, और फिर इसे आरंभ कर देगा। बाद में आने वाले प्रत्येक अन्य धागे को मुख्य थ्रेड के लिए ऑब्जेक्ट को प्रारंभ करने और अंततः लॉक को रिलीज़ करने की प्रतीक्षा करनी चाहिए। स्केल में सिंगलटन ऑब्जेक्ट्स को लागू करने का यही तरीका है।

आपके मामले में समानांतर संग्रह कार्यकर्ता थ्रेड doSomething को आमंत्रित करने के लिए सिंगलटन ऑब्जेक्ट तक पहुंचने का प्रयास करता है, लेकिन ऐसा तब तक नहीं कर सकता जब तक कि मुख्य धागे ऑब्जेक्ट को प्रारंभ करने को पूरा नहीं करता - इसलिए यह प्रतीक्षा करता है। दूसरी तरफ, मुख्य धागा कन्स्ट्रक्टर में इंतजार करता है जब तक कि समांतर ऑपरेशन पूरा नहीं होता है, जो सभी कार्यकर्ता धागे को पूरा करने पर सशर्त होता है - मुख्य धागे में सिंगलटन के लिए प्रारंभिक लॉक होता है। इसलिए, एक डेडलॉक होता है।

आप 2.10 से वायदा के साथ इस व्यवहार का कारण बन सकती है, या मात्र धागे के साथ, जिन्हें आप नीचे:

def execute(body: =>Unit) { 
    val t = new Thread() { 
    override def run() { 
     body 
    } 
    } 

    t.start() 
    t.join() 
} 

object ParCollection { 

    def doSomething() { println("Doing something") } 

    execute { 
    doSomething() 
    } 

} 

आरईपीएल में चिपकाएं, और उसके बाद लिखें:

scala> ParCollection 

और आरईपीएल लटका हुआ है।

+2

उत्कृष्ट स्पष्टीकरण, धन्यवाद! –

+1

समवर्ती अवरोध निष्पादन और आलसी प्रारंभिक अच्छी तरह से एक साथ खेल नहीं है। स्कैला (और जावा, उस मामले के लिए) में यह एक और सामान्य समस्या है। यह एसआईपी देखें: http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html – axel22

+0

रीटॉर्ट के रूप में नहीं, लेकिन मुझे लगता है कि यह डेवलपर्स के लिए एक गड़बड़ है। मैं आपके शुरुआती उत्तर और टिप्पणियों के लिए बहुत आभारी हूं, बहुत ही। मेरा मानना ​​है कि जवाब मेरे द्वारा क्रिस्टल स्पष्ट था। – matanster

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