जावेद जैसे संकलक क्या स्वचालित रूप से शुद्ध कार्यों का पता लगाते हैं और उन्हें समानांतर करते हैं?


12

शुद्ध कार्यों को पैरेललाइजिंग की सुविधा के लिए जाना जाता है। यह कार्यात्मक प्रोग्रामिंग के बारे में क्या है जो इसे स्वाभाविक रूप से समानांतर निष्पादन के लिए अनुकूल बनाता है?

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


7
सवाल केवल यह नहीं है कि क्या संकलक यह जान सकता है कि क्या कोई फ़ंक्शन शुद्ध है, बल्कि यह भी कि क्या यह समझदारी से शुद्ध कार्यों के समानांतर निष्पादन का समय निर्धारित कर सकता है। यह हर एक के लिए एक नया धागा बंद करने के लिए पर्याप्त नहीं है: यह अक्षम है। जीएचसी (हास्केल) आलस्य और "ग्रीन थ्रेड्स" का उपयोग करके इससे संबंधित है; अगर कोई अशुद्ध भाषा भी आजमाई जाती है, तो मुझे ईमानदारी से आश्चर्य होगा कि शुद्ध धागे को मुख्य अशुद्ध धागे के संबंध में सही ढंग से निर्धारित करने की अतिरिक्त कठिनाई को देखते हुए।
रेयान रीच

@RyanReich, क्या जावा जैसी अशुद्ध कार्यात्मक भाषा में कार्यात्मक प्रोग्रामिंग का उपयोग करने के कोई प्रदर्शन लाभ हैं? क्या कार्यात्मक प्रोग्रामिंग के लाभ विशुद्ध रूप से कार्यात्मक हैं जैसे कि मॉड्यूलर?
नवीन

@RyanReich जीएचसी प्रोग्रामर एनोटेट द्वारा समस्या का सामना करता है जब वे समानता चाहते हैं। पवित्रता का अर्थ है कि ये एनोटेशन कभी भी शब्दार्थ नहीं बदलते हैं, केवल प्रदर्शन। (समवर्ती तंत्र भी हैं जो समानता को जन्म दे सकते हैं, लेकिन यह मछली का एक अलग केतली है।)
डेरेक एल्किंस ने SE

@ नवीन को समानता के अलावा शुद्धिकरण के अन्य शुद्ध लाभ भी हैं, जैसे कि अधिक स्वतंत्रता पुनरावृत्ति कोड, संस्मरण और सामान्य उपसंचाई उन्मूलन। मैं गलत हो सकता है, लेकिन मुझे संदेह है कि javac शुद्धता का पता लगाने का प्रयास करता है, क्योंकि यह मुहावरेदार कोड में संभवतः काफी दुर्लभ है और सभी लेकिन सबसे तुच्छ मामलों के लिए कुछ हद तक मुश्किल है। उदाहरण के लिए, आपको यह जानना होगा कि कोई भी NullPointerExceptionएस नहीं होगा । इस पर आधारित अनुकूलन के लाभ भी संभवतः विशिष्ट जावा अनुप्रयोगों के लिए काफी कम हैं।
डेरेक एल्किंस ने SE

6
javac जावा कंपाइलर है, जो जावा सोर्स कोड लेता है और जावा बाइट कोड क्लास फाइल्स जेनरेट करता है। यह बहुत ही विवश है कि यह क्या कर सकता है (और माना जाता है) करते हैं। इसमें बाइट कोड क्लास फाइल में समानता लाने के लिए या अंतर्निहित अंतर्निहित तंत्र की स्वतंत्रता नहीं है।
एरिक इद्दत

जवाबों:


33

जब एक विधि एक शुद्ध कार्य है, तो यह पता लगाने के लिए पर्याप्त जेकाक जैसे कंपाइलर हैं।

यह "स्मार्ट पर्याप्त" का सवाल नहीं है। इसे शुद्धता विश्लेषण कहा जाता है और सामान्य मामले में यह काफी असंभव है: यह हॉल्टिंग समस्या को हल करने के बराबर है।

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

और यहां तक ​​कि उन मामलों में जहां यह काम करता है , एल्गोरिदम जटिल और महंगे हैं।

तो, यह समस्या # 1 है: यह केवल विशेष मामलों के लिए काम करती है

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

यह केवल तभी काम करता है, जब आपके पास पूरे कार्यक्रम का विश्लेषण होता है, जब पूरा कार्यक्रम एक ही भाषा में लिखा जाता है, और सभी को एक बार में एक साथ संकलित किया जाता है। आप किसी भी लाइब्रेरी का उपयोग नहीं कर सकते।

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

जैसा कि आप शायद अब तक अनुमान लगा चुके हैं, यह पता लगाना कि सामान्य स्थिति में एक संगणना कितनी देर तक असंभव है (हम यह भी पता नहीं लगा सकते हैं कि क्या यह एक परिमित राशि लेगा, अकेले कितना समय दें) और कठिन और महंगा भी विशेष मामला।

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

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

ध्यान दें कि, उदाहरण के लिए, हॉटस्पॉट सी 2 JIT कम्पाइलर वास्तव में करता है कुछ ऑटो vectorization, जो भी ऑटो चलाना का एक रूप है प्रदर्शन करते हैं।


खैर, "शुद्ध कार्य" की आपकी परिभाषा के आधार पर, कार्यान्वयन में अशुद्ध कार्यों का उपयोग करने की अनुमति दी जा सकती है।
डेडुप्लिकेटर

@Deduplicator ठीक है, की अपनी परिभाषा पर निर्भर करता है definition, एक विषम का उपयोग कर definitionके purityशायद अस्पष्ट है
बिल्ली

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

2
@aaartinus: इसके अलावा, मेरे जवाब का केवल बहुत अंत javac के लिए विशिष्ट है। मैं विशेष रूप से उल्लेख करता हूं , उदाहरण के लिए कि "यह केवल तभी काम करता है, जब आपके पास पूरे कार्यक्रम का विश्लेषण होता है, जब पूरे कार्यक्रम को एक ही भाषा में लिखा जाता है, और सभी को एक ही बार में संकलित किया जाता है।" यह C2 के लिए स्पष्ट रूप से सच है: यह केवल एक भाषा (JVM बाइटकोड) से संबंधित है, और एक बार में पूरे कार्यक्रम तक इसकी पहुंच है।
जोर्ग डब्ल्यू मित्तग

1
@ JörgWMittag मुझे पता है कि ओपी javac के बारे में पूछता है, लेकिन मुझे यकीन है कि वे मान रहे हैं कि javac अनुकूलन के लिए जिम्मेदार है। और यह कि वे शायद ही जानते हैं कि सी 2 है। मैं नहीं कह रहा हूं, आपका जवाब बुरा है। यह सिर्फ इतना है कि javac को कोई भी अनुकूलन करने देता है (उपयोग की तरह तुच्छताओं को छोड़कर StringBuilder) एक गैर-समझदारी है, इसलिए मैं इसे खारिज कर दूंगा और बस मान लूंगा, ओपी javac लिखता है, लेकिन हॉटस्पॉट। आपकी समस्या # 2 javac में कुछ भी अनुकूलन के खिलाफ एक बहुत अच्छा कारण है ।
मेआर्टिनस

5

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

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

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

यदि आप थ्रेड्स को गतिशील रूप से बनाते हैं, तो यह स्थिति चर का उपयोग करने से भी धीमा है। इसलिए, संकलक को पहले से चल रहे थ्रेड्स की एक निश्चित संख्या सेट करने की आवश्यकता होगी।

तो, आपके प्रश्न का उत्तर नहीं है , संकलक "स्मार्ट" नहीं हैं विशेष रूप से जावा दुनिया में शुद्ध कार्यों को ऑटो-समानांतर करने के लिए पर्याप्त है। वे ऑटो-समांतर नहीं द्वारा स्मार्ट हैं!


5
" वे उन्हें ऑटो-समानांतर नहीं करके स्मार्ट हैं! " : यह बहुत दूर जाता है। हालांकि यह सच है कि केवल अपने स्वयं के लिए हर संभव बिंदु पर समानांतर करना आम तौर पर अक्षम होगा, एक स्मार्ट कंपाइलर एक व्यावहारिक समानांतर रणनीति की पहचान करेगा। मुझे लगता है कि ज्यादातर लोग इसे समझते हैं, इसलिए जब हम ऑटो-समानांतरकरण के बारे में बात करते हैं, तो हमारा मतलब ऑटो-व्यावहारिक-समानांतरकरण है।
नट

@ नट: बहुत मुश्किल से। इसके लिए मिलीसेकंड के 100s के रनटाइम स्केल पर शुद्ध कार्यों की पहचान करने की आवश्यकता होती है, और कंपाइलर से अपेक्षा की जाती है कि वे लूप के रनटाइम के किसी भी विचार को प्राप्त करें जिसमें उनके पुनरावृत्तियों में स्थिरांक नहीं हैं (और जो मामले आप नहीं चाहते हैं) मूर्खतापूर्ण है।
जोशुआ

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

1
@ जोशुआ: वास्तव में एक जेआईटी कंपाइलर के लिए बहुत आसान है। जेआईटी कंपाइलर यह भी पता लगा सकता है कि एक फ़ंक्शन शुद्ध नहीं हो सकता है, लेकिन अभी तक किसी भी कॉल ने अशुद्ध व्यवहार का आह्वान नहीं किया है।
gnasher729

मैं @ जोशुआ से सहमत हूं। मेरे पास काम पर एक कठिन-से-समानांतर एल्गोरिदम है। मैंने मैन्युअल रूप से इसे समानांतर करने की कोशिश की है, यहां तक ​​कि कुछ सरलीकृत सन्निकटन (और इस तरह एल्गोरिथ्म को संशोधित) करके, और हर बार बुरी तरह से विफल रहा है। यहां तक ​​कि एक कार्यक्रम जो यह बताता है कि किसी चीज को समानांतर करना संभव है, अत्यंत कठिन है, भले ही यह वास्तव में इसे समानांतर करने की तुलना में बहुत सरल हो। याद रखें कि हम ट्यूरिंग-पूर्ण प्रोग्रामिंग भाषाओं के बारे में बात कर रहे हैं।
जूही
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.