जावा में पूंछ-पुनरावृत्ति के लिए अनुकूलन क्यों नहीं है?


92

मैंने जो पढ़ा है, उससे: इसका कारण यह है कि यह निर्धारित करना आसान नहीं है कि वास्तव में किस पद्धति को हम विरासत कहते हैं।

हालांकि, जावा में स्थिर तरीकों के लिए कम से कम पूंछ-पुनरावृत्ति अनुकूलन क्यों नहीं है और संकलक के साथ स्थिर तरीकों को कॉल करने के लिए उचित तरीका लागू करना है?

पूंछ-पुनरावृत्ति के लिए जावा का कोई समर्थन क्यों नहीं है?

मुझे यकीन नहीं है कि यहाँ कोई कठिनाई है।


सुझाए गए डुप्लिकेट के बारे में , जैसा कि Jörg W Mittag 1 द्वारा समझाया गया है :

  • दूसरा सवाल TCO के बारे में पूछता है, यह TRE के बारे में है। TRE TCO की तुलना में बहुत सरल है।
  • इसके अलावा, दूसरा सवाल यह पूछता है कि JVM भाषा संकलन पर कौन सी सीमाएं लागू करता है, जो JVM के संकलन की इच्छा रखते हैं, यह प्रश्न जावा के बारे में पूछता है, जो कि JVM द्वारा प्रतिबंधित नहीं होने वाली एक भाषा है, क्योंकि JVM कल्पना द्वारा बदला जा सकता है वही लोग जो जावा डिजाइन करते हैं।
  • और अंत में, TRE के बारे में JVM में कोई प्रतिबंध नहीं है, क्योंकि JVM में इंट्रा-विधि GOTO है, जो TRE के लिए आवश्यक है

1 तैयार किए गए बिंदुओं को कॉल करने के लिए जोड़ा गया स्वरूपण।


26
एरिक लिपर्ट को उद्धृत करने के लिए : "सुविधाएँ सस्ती नहीं हैं; वे बहुत महंगे हैं और उन्हें न केवल अपनी लागत का औचित्य साबित करना चाहिए, बल्कि उस बजट के साथ हमारे द्वारा किए जा सकने वाले सौ अन्य सुविधाओं को न करने के अवसर की लागत को उचित ठहराना होगा।" जावा को C / C ++ डेवलपर्स के लिए अपील करने के लिए डिज़ाइन किया गया था और उन भाषाओं में पूंछ पुनरावृत्ति अनुकूलन की गारंटी नहीं है।
डोभाल

5
सही है अगर मैं गलत हूँ, लेकिन एरिक लिप्टर सी # के लिए डिजाइनर है जो पूंछ पुनरावृत्ति अनुकूलन है?
सूचित 31

1
वह C # संकलक टीम पर है, हाँ।
डोभाल

10
जो मैं समझता हूं, जेआईटी यह कर सकती है , यदि कुछ शर्तें पूरी होती हैं , तो हो सकता है। तो व्यवहार में आप इस पर भरोसा नहीं कर सकते। लेकिन क्या C # करता है या नहीं, यह एरिक की बात से इतर है।
डोभाल

4
@InstructedA यदि आप थोड़ा गहरा खोदते हैं, तो आप देख सकते हैं कि यह 32-बिट JIT कंपाइलर में कभी नहीं किया गया है। 64-बिट JIT कई मायनों में नया और स्मार्ट है। यहां तक ​​कि नए प्रायोगिक कंपाइलर (दोनों 32 और 64-बिट के लिए) अभी तक स्मार्ट हैं, और आईएल में पूंछ-पुनरावृत्ति अनुकूलन का समर्थन करेंगे जो स्पष्ट रूप से इसके लिए नहीं पूछते हैं। एक और बिंदु है जिसे आपको ध्यान में रखने की आवश्यकता है - जेआईटी संकलक के पास बहुत समय नहीं है। वे गति के लिए भारी रूप से अनुकूलित हैं - सी ++ में संकलन के लिए घंटों लगने वाले अनुप्रयोग को अभी भी आईएल से एक सौ सौ एमएस में मूल निवासी (कम से कम आंशिक रूप से) जाने की आवश्यकता होगी।
लुआं

जवाबों:


132

जैसा कि इस वीडियो में ब्रायन गोएट्ज़ (ओरेकल में जावा लैंग्वेज आर्किटेक्ट) ने बताया है :

jdk classes में [...] कई सुरक्षा संवेदनशील तरीके हैं जो jdk लाइब्रेरी कोड और कॉलिंग कोड के बीच स्टैक फ्रेम की गिनती पर भरोसा करते हैं ताकि यह पता लगाया जा सके कि उन्हें कौन बुला रहा है।

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

इसके बाद उन्होंने उल्लेख किया कि यह प्राथमिकता नहीं है, लेकिन यह पूंछ पुनरावृत्ति है

अंत में काम हो जाएगा।

NB यह हॉटस्पॉट और OpenJDK पर लागू होता है, अन्य VMs भिन्न हो सकते हैं।


7
मुझे आश्चर्य है कि इस तरह से इस तरह के एक कट और सूखे जवाब है! लेकिन यह वास्तव में उत्तर की तरह लगता है - यह अब संभव है, पुराने तकनीकी कारणों से यह पहले से ही नहीं किया गया है, और इसलिए अब हम किसी के लिए यह तय करने के लिए इंतजार करते हैं कि यह लागू करने के लिए पर्याप्त है।
ब्रायन

1
क्यों नहीं एक समाधान लागू? अंडर-द-कवर लेबल-गोटो की तरह जो सिर्फ तर्कों के लिए नए मूल्यों के साथ विधि कॉल के शीर्ष पर कूदता है? यह एक संकलन-समय अनुकूलन होगा और स्टैक फ़्रेम को स्थानांतरित करने या सुरक्षा उल्लंघन का कारण बनने की आवश्यकता नहीं होगी।
जेम्स वाटकिंस

2
यह हमारे लिए बहुत बेहतर होगा यदि आप या यहाँ कोई और गहरी खुदाई कर सकता है और विशेष रूप से उन "सुरक्षा संवेदनशील तरीकों" को प्रदान कर सकता है। धन्यवाद!
सूचित

3
@InstructedA - देख securingjava.com/chapter-three/chapter-three-6.html जिनमें से कैसे जावा सुरक्षा प्रबंधक प्रणाली जावा 2. की रिहाई के लगभग काम एक विस्तृत वर्णन होता है
जूल्स

3
एक वर्कअराउंड दूसरी JVM भाषा का उपयोग करना है। उदाहरण के लिए, स्काला यह संकलक में करता है, रनटाइम पर नहीं।
जेम्स मूर

24

जावा में टेल कॉल ऑप्टिमाइज़ेशन नहीं है उसी कारण से अधिकांश अनिवार्यता वाली भाषाओं में यह नहीं है। इम्पीरेटिव लूप्स भाषा की पसंदीदा शैली है, और प्रोग्रामर टेल रिकर्सियन को अनिवार्य लूप के साथ बदल सकता है। जटिलता ऐसी विशेषता के लिए योग्य नहीं है जिसका उपयोग शैली के रूप में हतोत्साहित किया जाता है।

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


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

4
@amon James Gosling ने एक बार कहा था कि वह जावा में एक सुविधा नहीं जोड़ेंगे, जब तक कि कई लोग इसका अनुरोध नहीं करते हैं , और केवल तब ही वह इस पर विचार करेंगे। यदि उत्तर का हिस्सा वास्तव में "आप हमेशा एक forलूप का उपयोग कर सकते हैं" तो मुझे आश्चर्य नहीं होगा "(और इसी तरह प्रथम श्रेणी के कार्यों के लिए" ऑब्जेक्ट)। मैं इतनी दूर नहीं जाऊंगा कि इसे "अनिवार्यता" कहा जा सके, लेकिन मुझे नहीं लगता कि 1995 में यह बहुत अधिक मांग में था, जब शीर्ष चिंता शायद जावा की गति और जेनरिक की कमी थी।
डोभाल

7
@amon, एक सुरक्षा मॉडल ने मुझे एक पूर्व-मौजूदा भाषा में TCO को न जोड़ने के एक वैध कारण के रूप में प्रहार किया, लेकिन पहली बार में इसे भाषा में डिज़ाइन नहीं करने का एक खराब कारण। आप एक प्रमुख प्रोग्रामर-दृश्यमान सुविधा को एक मामूली पीछे के दृश्य सुविधा को शामिल करने के लिए बाहर नहीं फेंकते हैं। "जावा 8 में TCO क्यों नहीं है" "Java 1.0 में TCO क्यों नहीं है" की तुलना में एक बहुत अलग प्रश्न है? मैं उत्तर दे रहा था।
कार्ल नेवलेफेल्ट

3
@, आप किसी भी पुनरावर्ती कार्य को पुनरावृति में बदल सकते हैं । (मैं, मैं एक उदाहरण लिखा है, तो यहाँ )
एलेन

3
@ZanLynx यह समस्या के प्रकार पर निर्भर करता है। उदाहरण के लिए, विज़िटर पैटर्न में एफसीओ के साथ कुछ नहीं होने के दौरान टीसीओ (संरचना और आगंतुक की बारीकियों के आधार पर) से लाभ हो सकता है। राज्य मशीनों के माध्यम से जाना समान है हालांकि ट्रम्पोलिन का उपयोग करके परिवर्तन थोड़ा अधिक स्वाभाविक लगता है (समस्या के आधार पर)। इसके अलावा, जब आप तकनीकी रूप से, पेड़ों का उपयोग कर सकते हैं तो लूप्स का उपयोग करें मुझे विश्वास है कि आम सहमति बहुत अधिक प्राकृतिक है (डीएफएस के लिए समान है हालांकि इस मामले में आप टीसीओ के साथ स्टैक सीमा के कारण पुनरावृत्ति से बच सकते हैं)।
मैकीज पाइचोटका

5

जावा में लंबा कॉल ऑप्टिमाइज़ेशन नहीं है क्योंकि JVM में टेल कॉल के लिए बाईटेकोड नहीं है (कुछ अज्ञात रूप से अज्ञात फ़ंक्शन पॉइंटर में, जैसे कि कुछ व्यवहार्य में एक विधि)।

यह सामाजिक (और शायद तकनीकी) कारणों के लिए लग रहा है, जेवीएम में एक नया बाईटेकोड संचालन जोड़ रहा है (जो कि उस जेवीएम के पहले संस्करणों के साथ असंगत बना देगा) जेवीएम कल्पना के मालिक के लिए बहुत मुश्किल है।

जेवीएम कल्पना में एक नया बाईटेकोड न जोड़ने के तकनीकी कारणों में यह तथ्य शामिल है कि वास्तविक जीवन के जेवीएम कार्यान्वयन बहुत जटिल सॉफ़्टवेयर टुकड़े हैं (जैसे कि कई जेआईटी अनुकूलन के कारण यह कर रहे हैं)।

कुछ अज्ञात फ़ंक्शन में टेल कॉल के लिए वर्तमान स्टैक फ्रेम को एक नए के साथ बदलने की आवश्यकता होती है, और उस ऑपरेशन को जेवीएम में बैठना चाहिए (यह न केवल बायटेकोड जनरेटिंग कंपाइलर को बदलने का मामला है)।


17
सवाल पूंछ कॉल के बारे में नहीं है, यह पूंछ पुनरावृत्ति के बारे में है। और सवाल JVM बाइटकोड भाषा के बारे में नहीं है, यह जावा प्रोग्रामिंग भाषा के बारे में है, जो पूरी तरह से अलग भाषा है। स्काला जेवीएम बायटेकोड (अन्य के बीच) में संकलन करता है और इसमें पूंछ-पुनरावृत्ति उन्मूलन है। जेवीएम पर स्कीम के कार्यान्वयन में फुल प्रॉपर टेल-कॉल्स हैं। जावा 7 (JVM Spec, 3rd Ed।) ने एक नया बायटेकोड जोड़ा। आईबीएम का J9 JVM एक विशेष बायोटेक की आवश्यकता के बिना भी TCO प्रदर्शन करता है।
जोर्ग डब्ल्यू मित्तग

1
@ JörgWMittag: यह सच है, लेकिन फिर, मुझे आश्चर्य है कि अगर यह वास्तव में सच है कि जावा प्रोग्रामिंग भाषा में उचित टेल कॉल नहीं है। यह राज्य के लिए कि जावा प्रोग्रामिंग भाषा नहीं है और अधिक सटीक हो सकता है , उचित पूंछ कॉल कर पाने के कल्पना यह जनादेश में कि कुछ भी नहीं है। (यह है: मुझे यकीन नहीं है कि कल्पना में कुछ भी वास्तव में पूंछ कॉल को खत्म करने से एक कार्यान्वयन को मना करता है। यह बस उल्लेख नहीं किया गया है।)
बर्बाद करें

4

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

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


2

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

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