पाश उलटा तकनीक क्या है?


89

मैं एक दस्तावेज के माध्यम से जा रहा था जो जावा के लिए सिर्फ-इन-टाइम कंपाइलर (जेआईटी) अनुकूलन तकनीकों के बारे में बात करता है । उनमें से एक "लूप इनवर्जन" था। और दस्तावेज़ कहता है:

आप एक नियमित whileलूप को लूप से बदल देते हैं do-while। और do-whileलूप को एक ifखंड के भीतर सेट किया गया है । यह प्रतिस्थापन दो कम कूदता है।

पाश उलटा कैसे काम करता है और यह हमारे कोड पथ को कैसे अनुकूलित करता है?

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


2
यह कुछ ऐसा नहीं है जो आप अपने स्रोत कोड के लिए करेंगे। यह देशी कोड स्तर पर होता है।
मार्को टोपोलनिक 15

2
@MarkoTopolnik मुझे पता है। लेकिन मैं यह जानना चाहता हूं कि देशी कोड स्तर में जेआईटी यह कैसे करता है। धन्यवाद।
कोशिश कर रहा है

1
ओह कूल, इस बारे में बहुत सारे उदाहरणों के साथ एक विकिपीडिया पेज है । en.wikipedia.org/wiki/Loop_inversion । सी उदाहरण जावा में बस के रूप में मान्य है।
बेंजामिन ग्रुएनबाम

कुछ समय पहले SO पर एक प्रश्न से प्रेरित होकर मैंने इस मामले में एक छोटा शोध किया है, हो सकता है कि परिणाम आपके लिए उपयोगी हों: stackoverflow.com/questions/16205843/java-loop-efficiency/…
Siem एडमिरियन डिक्शन

क्या यह वही है जहां लूप की स्थिति आमतौर पर अंत में डाल दी जाती है (भले ही वहाँ कुछ कम छलांग लगाई जाए), बस इतना है कि कम कूद निर्देश (1 बनाम 2 प्रति चलना) हैं?
एक्सट्रीमैक्स 5

जवाबों:


108
while (condition) { 
  ... 
}

कार्यप्रवाह:

  1. हालत की जांच;
  2. अगर झूठ है, तो लूप के बाहर कूदो;
  3. एक चलना;
  4. ऊपर से कूदो।

if (condition) do {
  ...
} while (condition);

कार्यप्रवाह:

  1. हालत की जांच;
  2. अगर गलत है, तो लूप से परे कूदो;
  3. एक चलना;
  4. हालत की जांच;
  5. यदि सही है, तो चरण 3 पर जाएं।

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

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

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

महत्वपूर्ण लेख

कृपया इसे स्रोत कोड स्तर पर अनुकूलित करने के तरीके के रूप में लें। यह पूरी तरह से गुमराह किया जाएगा, जैसा कि पहले से ही आपके सवाल से स्पष्ट है, पहले रूप से दूसरे में परिवर्तन जेआईटी संकलक रूटीन के मामले में, पूरी तरह से अपने दम पर करता है।


51
यह नोट अंत में एक बहुत महत्वपूर्ण बात है।
टीजे क्राउडर

2
@AdamSiemion: दिए गए do-whileस्रोत कोड के लिए उत्पन्न बायटेकोड अप्रासंगिक है, क्योंकि हम वास्तव में ऐसा नहीं लिखते हैं। हम whileलूप लिखते हैं और संकलक और जेआईटी को हमारे लिए (लूप इनवर्जन के माध्यम से) इम्प्रूव करने के लिए बेहतर बनाता है।
टीजे क्राउडर

1
@TJCrowder +1 उपरोक्त के लिए, प्लस टू एडम: जेआईटी संकलक के अनुकूलन के बारे में सोचते समय बायटेकोड पर कभी विचार न करें । वास्तविक JIT संकलित कोड की तुलना में बायटेकोड जावा स्रोत कोड के बहुत करीब है। वास्तव में, आधुनिक भाषाओं में प्रवृत्ति भाषा के बंटवारे के हिस्से के रूप में बिल्कुल भी नहीं है।
मार्को टोपोलनिक

1
अतिरिक्त जानकारीपूर्ण होगा महत्वपूर्ण नोट थोड़ा और अधिक समझाया गया था। इसे पूरी तरह से गुमराह क्यों किया जाएगा ?
arsaKasra

2
@arsaKasra यह गलत है क्योंकि स्रोत कोड में सामान्य पठनीयता और स्थिरता ट्रम्प अनुकूलन है। विशेष रूप से रहस्योद्घाटन के साथ कि जेआईटी आपके लिए ऐसा करता है, आपको अपने दम पर (बहुत सूक्ष्म) अनुकूलन का प्रयास नहीं करना चाहिए।
रेडियोडफ

24

यह एक लूप को अनुकूलित कर सकता है जिसे हमेशा कम से कम एक बार निष्पादित किया जाता है।

एक नियमित whileलूप हमेशा कम से कम एक बार शुरू में वापस कूद जाएगा और अंत में एक बार अंत में कूद जाएगा। एक बार चलने वाले साधारण लूप का एक उदाहरण:

int i = 0;
while (i++ < 1) {
    //do something
}  

do-whileदूसरी ओर एक लूप पहली और आखिरी छलांग को छोड़ देगा। यहां ऊपर वाले के बराबर लूप है, जो बिना जंप के चलेगा:

int i = 0;
if (i++ < 1) {
    do {
        //do something
    } while (i++ < 1); 
}

+1 सही और पहले होने के लिए, कृपया एक कोड उदाहरण जोड़ने पर विचार करें। कुछ ऐसा boolean b = true; while(b){ b = maybeTrue();}करना boolean b;do{ b = maybeTrue();}while(b);चाहिए जो पर्याप्त हो।
बेंजामिन ग्रुएनबाम

कोई चिंता नहीं। यह उत्तर की प्रारंभिक लाइन को अमान्य करता है, fwiw। :-)
टीजे क्राउडर

@ टीजे खैर, यह अभी भी एक लूप को ऑप्टिमाइज़ नहीं करेगा जो दर्ज नहीं किया गया है, दोनों मामलों में एक कूद होगा।
केपील

आह येस। क्षमा करें, मैं यह पढ़ रहा था कि इसका मतलब यह है कि आप इसे उन छोरों पर लागू नहीं कर सकते जो कम से कम एक बार लूप नहीं करते थे (इसके बजाय यह उनकी मदद नहीं करता है)। अब तुम्हारे साथ। :-)
टीजे क्राउडर

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

3

चलो उनके माध्यम से चलते हैं:

whileसंस्करण:

void foo(int n) {
    while (n < 10) {
       use(n);
       ++n;
    }
    done();
}
  1. पहले हम परीक्षण nऔर कूद done();अगर हालत सच नहीं है।
  2. फिर हम उपयोग और वेतन वृद्धि करते हैं n
  3. अब हम वापस हालत में आ गए।
  4. कुल्ला, दोहराना।
  5. जब हालत अब सच नहीं है, हम कूदते हैं done()

do-whileसंस्करण:

(याद रखें, हम वास्तव में स्रोत कोड में ऐसा नहीं करते हैं [जो रखरखाव के मुद्दों को पेश करेगा], संकलनकर्ता / JIT हमारे लिए करता है।)

void foo(int n) {
    if (n < 10) {
        do {
            use(n);
            ++n;
        }
        while (n < 10);
    }
    done();
}
  1. पहले हम परीक्षण nऔर कूद done();अगर हालत सच नहीं है।
  2. फिर हम उपयोग और वेतन वृद्धि करते हैं n
  3. अब हम स्थिति का परीक्षण करते हैं और यदि यह सही है तो वापस कूदते हैं।
  4. कुल्ला, दोहराना।
  5. जब हालत अब सच नहीं है, हम (नहीं कूद) प्रवाह done()

उदाहरण के लिए, अगर nबाहर होना शुरू होता है , तो 9हम कभी भी do-whileसंस्करण में नहीं कूदते हैं , जबकि मेंwhile संस्करण में हमें शुरुआत में वापस कूदना पड़ता है, परीक्षण करते हैं, और फिर अंत में वापस कूदते हैं जब हम देखते हैं कि यह सच नहीं है ।


3

लूप उलटा एक प्रदर्शन अनुकूलन तकनीक है जो प्रदर्शन में सुधार करता है क्योंकि प्रोसेसर कम निर्देशों के साथ एक ही परिणाम प्राप्त कर सकता है। यह ज्यादातर सीमा स्थितियों में प्रदर्शन में सुधार करना चाहिए।

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

विकिपीडिया का एक बहुत अच्छा उदाहरण है और मैं इसे यहाँ फिर से समझा रहा हूँ।

 int i, a[100];
  i = 0;
  while (i < 100) {
    a[i] = 0;
    i++;
  }

संकलक द्वारा परिवर्तित किया जाएगा

  int i, a[100];
  i = 0;
  if (i < 100) {
    do {
      a[i] = 0;
      i++;
    } while (i < 100);
  }

यह प्रदर्शन के लिए कैसे अनुवाद करता है? जब i का मान 99 होता है, तो प्रोसेसर को GOTO (जो पहले मामले में आवश्यक होता है) करने की आवश्यकता नहीं है। इससे प्रदर्शन में सुधार होता है।

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