2008-09-02 22 views
32

वे क्या हैं और वे किसके लिए अच्छे हैं?मुझे बस निरंतरता नहीं मिलती है!

मेरे पास सीएस डिग्री नहीं है और मेरी पृष्ठभूमि वीबी 6 -> एएसपी -> एएसपी.NET/C# है। क्या कोई इसे स्पष्ट और संक्षिप्त तरीके से समझा सकता है?

उत्तर

41

कल्पना करें कि आपके कार्यक्रम में प्रत्येक पंक्ति एक अलग कार्य थी। प्रत्येक पैरामीटर के रूप में स्वीकार करता है, निष्पादित करने के लिए अगली पंक्ति/फ़ंक्शन।

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

+0

वाह, जो वास्तव में समझ में आया। धन्यवाद! – minimalpop

+0

हां, बहुत अच्छी व्याख्या! मेरे द्वारा +1;) – Alfred

+4

मुझे भी यह पसंद है, लेकिन कौन सा हिस्सा वास्तव में निरंतरता है? – user2023370

9

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

निरंतरता अत्यंत बहुमुखी हैं और निष्पादन स्थिति को सहेजने और बाद में इसे फिर से शुरू करने का एक तरीका है। यहाँ एक सहकारी बहु सूत्रण पर्यावरण योजना में निरंतरता का उपयोग करने का एक छोटा सा उदाहरण है:

(मान लें कि आपरेशन enqueue और विपंक्ति काम एक वैश्विक कतार यहाँ नहीं परिभाषित पर अपेक्षा के अनुरूप)

(define (fork) 
    (display "forking\n") 
    (call-with-current-continuation 
    (lambda (cc) 
    (enqueue (lambda() 
       (cC#f))) 
    (cC#t)))) 

(define (context-switch) 
    (display "context switching\n") 
    (call-with-current-continuation 
    (lambda (cc) 
    (enqueue 
     (lambda() 
     (cc 'nothing))) 
    ((dequeue))))) 

(define (end-process) 
    (display "ending process\n") 
    (let ((proc (dequeue))) 
    (if (eq? proc 'queue-empty) 
     (display "all processes terminated\n") 
     (proc)))) 

इस तीन क्रियाओं में प्रावधान है कि एक फ़ंक्शन का उपयोग कर सकते हैं - कांटा, संदर्भ-स्विच, और अंत-प्रक्रिया। कांटा ऑपरेशन धागे को फोर्क करता है और एक उदाहरण में #t और दूसरे में #f देता है। संदर्भ-स्विच ऑपरेशन थ्रेड के बीच स्विच करता है, और एंड-प्रोसेस एक थ्रेड को समाप्त करता है।

(define (test-cs) 
    (display "entering test\n") 
    (cond 
    ((fork) (cond 
       ((fork) (display "process 1\n") 
         (context-switch) 
         (display "process 1 again\n")) 
       (else (display "process 2\n") 
        (end-process) 
        (display "you shouldn't see this (2)")))) 
    (else (cond ((fork) (display "process 3\n") 
         (display "process 3 again\n") 
         (context-switch)) 
       (else (display "process 4\n"))))) 
    (context-switch) 
    (display "ending process\n") 
    (end-process) 
    (display "process ended (should only see this once)\n")) 

उत्पादन इस के समान

entering test 
forking 
forking 
process 1 
context switching 
forking 
process 3 
process 3 again 
context switching 
process 2 
ending process 
process 1 again 
context switching 
process 4 
context switching 
context switching 
ending process 
ending process 
ending process 
ending process 
ending process 
ending process 
all processes terminated 
process ended (should only see this once) 

वे जो forking और एक कक्षा में सूत्रण का अध्ययन किया है अक्सर दिया जाता है उदाहरण होना चाहिए:

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

पीएस - मुझे लगता है कि मुझे लिस्प में ऐसा कुछ याद है, इसलिए यदि आप पेशेवर कोड देखना चाहते हैं तो आपको पुस्तक को देखना चाहिए।

4

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

2

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

एक कार्यक्रम में प्रत्येक संभावित "लाइव" बिंदु स्मृति में किसी भी बिंदु पर कौन सा नियंत्रण कूद सकता है, एक अर्थ में, एक सक्रिय निरंतरता है।अन्य बिंदुओं पर पहुंचा जा सकता है जो संभावित रूप से सक्रिय निरंतरताएं हैं, लेकिन, बिंदु पर अधिक, वे निरंतर सक्रिय निरंतरताओं में से एक या अधिक तक पहुंचने के परिणामस्वरूप संभावित रूप से "गणना" (गतिशील रूप से, संभवतः) हैं।

यह निरंतरता के पारंपरिक परिचय में जगह से थोड़ा सा लगता है, जिसमें निष्पादन के सभी लंबित धागे स्पष्ट रूप से स्थैतिक कोड में निरंतरता के रूप में प्रतिनिधित्व किए जाते हैं; लेकिन यह इस तथ्य को ध्यान में रखता है कि, सामान्य प्रयोजन कंप्यूटर पर, पीसी एक निर्देश अनुक्रम को इंगित करता है जो संभावित रूप से उस निर्देश अनुक्रम के एक हिस्से का प्रतिनिधित्व करने वाली स्मृति की सामग्री को बदल सकता है, इस प्रकार अनिवार्य रूप से एक नया (या संशोधित, यदि आप करेंगे) फ्लाई पर निरंतरता, जो वास्तव में उस सृजन/संशोधन से पहले निरंतरता की सक्रियताओं के रूप में मौजूद नहीं है।

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

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

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

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

11

शायद आप उन्हें सोचने से बेहतर समझते हैं कि आपने किया था।

अपवाद "ऊपर-केवल" निरंतरता का एक उदाहरण हैं। वे किसी समस्या को इंगित करने के लिए अपवाद हैंडलर को कॉल करने के लिए स्टैक को गहराई से कोड की अनुमति देते हैं।

अजगर उदाहरण:

try: 
    broken_function() 
except SomeException: 
    # jump to here 
    pass 

def broken_function(): 
    raise SomeException() # go back up the stack 
    # stuff that won't be evaluated 

जेनरेटर "नीचे-ओनली" निरंतरता के उदाहरण हैं। वे कोड को एक लूप को पुन: प्रस्तुत करने की अनुमति देते हैं, उदाहरण के लिए, नए मान बनाने के लिए।

अजगर उदाहरण:

def sequence_generator(i=1): 
    while True: 
     yield i # "return" this value, and come back here for the next 
     i = i + 1 

g = sequence_generator() 
while True: 
    print g.next() 

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

7

निरंतरता के बारे में सोचने का एक तरीका प्रोसेसर स्टैक के रूप में है।जब आप "कॉल-इन-वर्तमान-निरंतरता सी" कहते हैं तो यह आपके फ़ंक्शन "सी" को कॉल करता है, और "सी" में पारित पैरामीटर आपके वर्तमान स्वचालित स्टैक पर आपके सभी स्वचालित चर के साथ होता है (अभी तक एक और फ़ंक्शन के रूप में दर्शाया गया है, इसे कॉल करें "k ")। इस बीच प्रोसेसर एक नया ढेर बनाने से शुरू होता है। जब आप "के" कहते हैं तो यह मूल स्टैक पर "सबराउटिन से वापस लौटाता है" (आरटीएस) निर्देश निष्पादित करता है, जो आपको मूल "कॉल-इन-वर्तमान-निरंतरता" ("कॉल-सीसी" के संदर्भ में वापस ले जाता है चालू) और आपके कार्यक्रम को पहले के रूप में जारी रखने की इजाजत दी। यदि आपने "के" पर पैरामीटर पारित किया है तो यह "कॉल-सीसी" का वापसी मान बन जाता है।

अपने मूल स्टैक के दृष्टिकोण से, "कॉल-सीसी" सामान्य फ़ंक्शन कॉल की तरह दिखता है। "सी" के दृष्टिकोण से, आपका मूल ढेर एक ऐसे फ़ंक्शन जैसा दिखता है जो कभी वापस नहीं आता है।

गणितज्ञ के बारे में एक पुराना मजाक है जिसने पिंजरे में एक शेर पर कब्जा कर लिया है, उसे बंद कर दिया है, और खुद को पिंजरे से बाहर घोषित कर दिया है जबकि बाकी सब कुछ (शेर समेत) इसके अंदर था। निरंतरता पिंजरे की तरह थोड़ी सी है, और "सी" गणितज्ञ की तरह थोड़ा सा है। आपका मुख्य कार्यक्रम सोचता है कि "सी" इसके अंदर है, जबकि "सी" का मानना ​​है कि आपका मुख्य कार्यक्रम "के" के अंदर है।

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

2

सी # में, आपके पास दो निरंतरताएं हैं। एक, return के माध्यम से पहुंचा, इसे एक विधि से जारी रखा जाता है जहां इसे कहा जाता था। दूसरा, throw के माध्यम से पहुंचा, एक विधि निकटतम मिलान catch पर जारी रखने देता है।

कुछ भाषाएं आपको इन बयानों को प्रथम श्रेणी के मूल्यों के रूप में मानने देती हैं, ताकि आप उन्हें असाइन कर सकें और उन्हें चर के चारों ओर पास कर सकें। इसका अर्थ यह है कि आप return या throw के मान को रोक सकते हैं और बाद में उन्हें कॉल कर सकते हैं जब आप वास्तव में वापस लौटने या फेंकने के लिए तैयार हैं।

Continuation callback = return; 
callMeLater(callback); 

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

मैं उन दो परियोजनाओं में उनका उपयोग कर रहा हूं जिन पर मैं काम कर रहा हूं। एक में, मैं उनका उपयोग कर रहा हूं इसलिए मैं प्रोग्राम को निलंबित कर सकता हूं, जबकि मैं नेटवर्क पर आईओ की प्रतीक्षा कर रहा हूं, फिर इसे फिर से शुरू करें। दूसरी तरफ, मैं एक प्रोग्रामिंग भाषा लिख ​​रहा हूं जहां मैं उपयोगकर्ता को निरंतरता-मूल्यों तक पहुंच प्रदान करता हूं ताकि वे return और throw स्वयं के लिए लिख सकें - या while लूप जैसे किसी भी अन्य नियंत्रण प्रवाह - मुझे इसके बिना ऐसा करने की आवश्यकता है उन्हें।

1

धागे के बारे में सोचें। एक थ्रेड चलाया जा सकता है, और आप इसकी गणना का परिणाम प्राप्त कर सकते हैं। एक निरंतरता एक धागा है जिसे आप प्रतिलिपि बना सकते हैं, ताकि आप दो बार समान गणना चला सकें।

1

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