Kotlin Coroutine में फंक्शन सस्पेंड का क्या मतलब है


118

मैं Kotlin Coroutine पढ़ रहा हूं और जानता हूं कि यह suspendफ़ंक्शन पर आधारित है। लेकिन क्या suspendमतलब है?

Coroutine या फ़ंक्शन निलंबित हो जाता है?

से https://kotlinlang.org/docs/reference/coroutines.html

मूल रूप से, कॉरटुएंट ऐसी संगणनाएं होती हैं जिन्हें एक धागे को अवरुद्ध किए बिना निलंबित किया जा सकता है

मैंने सुना है कि लोग अक्सर "फंक्शन सस्पेंड" करते हैं। लेकिन मुझे लगता है कि यह कोरटाइन है जो निलंबित हो जाता है क्योंकि यह कार्य समाप्त होने की प्रतीक्षा कर रहा है? "सस्पेंड" का आमतौर पर मतलब होता है "युद्ध विराम", इस मामले में कॉरटीन बेकार है।

We क्या हमें यह कहना चाहिए कि धनिया निलंबित है?

किस कोरटाइन को निलंबित किया जाता है?

से https://kotlinlang.org/docs/reference/coroutines.html

सादृश्य जारी रखने के लिए, प्रतीक्षा करना () एक निलंबित कार्य हो सकता है (इसलिए async {} ब्लॉक से भी कॉल करने योग्य) जो कुछ गणना किए जाने तक एक coroutine को निलंबित कर देता है और उसका परिणाम देता है:

async { // Here I call it the outer async coroutine
    ...
    // Here I call computation the inner coroutine
    val result = computation.await()
    ...
}

That यह कहता है कि "जब तक कुछ गणना नहीं की जाती है, तब तक एक कोरटाइन को निलंबित कर दिया जाता है", लेकिन कोरआउट एक हल्के धागे की तरह है। तो अगर कोरटाइन को निलंबित कर दिया जाता है, तो गणना कैसे की जा सकती है?

हम देखते हैं awaitकि इसे चालू किया गया है computation, इसलिए यह हो सकता है asyncकि रिटर्न Deferred, जिसका अर्थ है कि यह एक और कोरआउट शुरू कर सकता है

fun computation(): Deferred<Boolean> {
    return async {
        true
    }
}

That उद्धरण कहता है कि एक कोरटाइन को निलंबित करता है । क्या इसका मतलब suspendबाहरी asyncकोरआउट, या suspendआंतरिक computationकोरआउट है?

क्या suspendमतलब है कि जबकि बाहरी asynccoroutine (प्रतीक्षा कर रहा है awaitआंतरिक के लिए) computationसमाप्त करने के लिए coroutine, यह (बाहरी asynccoroutine) idles (इसलिए नाम को निलंबित) और रिटर्न धागा थ्रेड पूल के लिए, और जब बच्चे computationcoroutine खत्म, यह (बाहरी asynccoroutine ) उठता है, पूल से एक और धागा लेता है और जारी रहता है?

मेरे द्वारा धागे का उल्लेख करने का कारण https://kotlinlang.org/docs/tutorials/coroutines-basic-jvm.html है।

थ्रेड को पूल में लौटाया जाता है, जबकि कॉरटीन इंतज़ार कर रहा है, और जब वेटिंग पूरी हो जाती है, तो कॉरटीन पूल में एक मुक्त थ्रेड पर फिर से शुरू होता है

जवाबों:


113

निलंबित कार्य सब कुछ कोरआउट के केंद्र में हैं। एक निलंबित फ़ंक्शन केवल एक फ़ंक्शन है जिसे बाद में रोका जा सकता है और फिर से शुरू किया जा सकता है। वे लंबे समय तक चलने वाले ऑपरेशन को अंजाम दे सकते हैं और बिना रुके इसके पूरा होने का इंतजार करते हैं।

एक निलंबित फ़ंक्शन का सिंटैक्स suspendकीवर्ड के अतिरिक्त को छोड़कर एक नियमित फ़ंक्शन के समान है । यह एक पैरामीटर ले सकता है और एक रिटर्न प्रकार हो सकता है। हालाँकि, निलंबित कार्य केवल किसी अन्य निलंबित फ़ंक्शन द्वारा या एक कोरआउट के भीतर लागू किए जा सकते हैं।

suspend fun backgroundTask(param: Int): Int {
     // long running operation
}

हुड के तहत, सस्पेंड फ़ंक्शन कीवर्ड के बिना संकलक द्वारा किसी अन्य फ़ंक्शन में कनवर्ट किए जाते हैं, जो प्रकार के अतिरिक्त पैरामीटर लेता है Continuation<T>। उदाहरण के लिए ऊपर का कार्य, संकलक द्वारा इसमें परिवर्तित किया जाएगा:

fun backgroundTask(param: Int, callback: Continuation<Int>): Int {
   // long running operation
}

Continuation<T> एक इंटरफ़ेस है जिसमें दो फ़ंक्शन होते हैं जो कि कॉरटॉयइन को एक रिटर्न वैल्यू या एक अपवाद के साथ फिर से शुरू करने के लिए आमंत्रित किया जाता है यदि फ़ंक्शन निलंबित होने के दौरान कोई त्रुटि हुई थी।

interface Continuation<in T> {
   val context: CoroutineContext
   fun resume(value: T)
   fun resumeWithException(exception: Throwable)
}

4
एक और रहस्य का खुलासा! महान!
विंडराइडर

16
मुझे आश्चर्य है कि इस समारोह को वास्तव में कैसे रोका गया है? वे हमेशा कहते हैं कि suspend funरोका जा सकता है लेकिन वास्तव में कैसे?
विंडराइडर

2
@WindRider इसका मतलब सिर्फ इतना है कि वर्तमान धागा कुछ अन्य कोरटाइन को निष्पादित करना शुरू कर देता है, और बाद में इस पर वापस आ जाएगा।
जोफ्री

2
मैंने "रहस्यमय" तंत्र का पता लगा लिया है। टूल्स> कोटलिन> बायटेकोड> डीकॉम्पाइल बीटीएन की मदद से इसे आसानी से अनावरण किया जा सकता है। यह दिखाता है कि तथाकथित "निलंबन बिंदु" कैसे लागू किया जाता है - निरंतरता और इसी तरह। कोई भी अपने लिए एक नज़र रख सकता है।
विंडराइडर

4
@buzaa यहां रोमन एलेकारोव द्वारा 2017 से एक बात की गई है जो इसे बाइटकोड स्तर पर बताती है।
मार्को टोपोलनिक

30

यह समझने के लिए कि वास्तव में कॉरआउट को निलंबित करने का क्या मतलब है, मेरा सुझाव है कि आप इस कोड के माध्यम से जाएं:

import kotlinx.coroutines.Dispatchers.Unconfined
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

var continuation: Continuation<Int>? = null

fun main() = runBlocking {
    launch(Unconfined) {
        val a = a()
        println("Result is $a")
    }
    10.downTo(0).forEach {
        continuation!!.resume(it)
    }
}

suspend fun a(): Int {
    return b()
}

suspend fun b(): Int {
    while (true) {
        val i = suspendCoroutine<Int> { cont -> continuation = cont }
        if (i == 0) {
            return 0
        }
    }
}

UnconfinedCoroutine डिस्पैचर के जादू समाप्त coroutine भेजने और हमें सीधे नंगे coroutines पर ध्यान केंद्रित करने की अनुमति देता है।

launchब्लॉक के अंदर का कोड launchकॉल के एक भाग के रूप में, वर्तमान थ्रेड पर तुरंत निष्पादित करना शुरू कर देता है । क्या होता है इस प्रकार है:

  1. मूल्यांकन करना val a = a()
  2. यह जंजीर b(), पहुंचने तक suspendCoroutine
  3. फ़ंक्शन b()पास किए गए ब्लॉक को निष्पादित करता है suspendCoroutineऔर फिर एक विशेष COROUTINE_SUSPENDEDमूल्य देता है । यह मान Kotlin प्रोग्रामिंग मॉडल के माध्यम से देखने योग्य नहीं है, लेकिन यह है कि संकलित जावा विधि क्या करती है।
  4. फ़ंक्शन a(), इस वापसी मूल्य को देखते हुए, स्वयं भी इसे लौटाता है।
  5. launchब्लॉक एक ही करता है और नियंत्रण अब के बाद लाइन में लौट launchमंगलाचरण:10.downTo(0)...

ध्यान दें, इस बिंदु पर, आपके पास समान प्रभाव होता है जैसे कि launchब्लॉक के अंदर कोड और आपका fun mainकोड समवर्ती रूप से निष्पादित हो रहा है। यह सिर्फ ऐसा होता है कि यह सब एक ही मूल धागे पर हो रहा है इसलिए launchब्लॉक "निलंबित" है।

अब, forEachलूपिंग कोड के अंदर , प्रोग्राम पढ़ता है continuationकि b()फ़ंक्शन ने लिखा है और resumesइसके मूल्य के साथ 10resume()इस तरह से कार्यान्वित किया जाता है जैसे यह होगा कि suspendCoroutineकॉल आपके द्वारा पास किए गए मान के साथ लौटा है। इसलिए आप अचानक अपने आप को क्रियान्वित करने के बीच में पाते हैं b()। आपके द्वारा resume()असाइन किया गया मान iऔर विरुद्ध चेक किया गया मान 0। यदि यह शून्य नहीं है, तो while (true)लूप अंदर जाता है b(), फिर से पहुंचता है suspendCoroutine, जिस पर आपका resume()कॉल रिटर्न होता है, और अब आप एक अन्य लूपिंग चरण से गुजरते हैं forEach()। यह तब तक चलता है जब तक आप फिर से शुरू करते हैं 0, तब printlnबयान चलता है और कार्यक्रम पूरा होता है।

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

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


19

सबसे पहले, इस IMO को समझने के लिए सबसे अच्छा स्रोत रोमन एलिफ़ारोव द्वारा "डीप डाइव इन कोराउटिन्स" है।

Coroutine या फ़ंक्शन निलंबित हो जाता है?

एक निलंबित कॉलिंग ing समारोह को निलंबित रों coroutine, वर्तमान धागा अर्थ एक और coroutine को क्रियान्वित करने शुरू कर सकते हैं। इसलिए, कोरटाइन को फ़ंक्शन के बजाय निलंबित करने के लिए कहा जाता है।

वास्तव में, इस कारण से निलंबित कार्यों के कॉल साइटों को "निलंबन बिंदु" कहा जाता है।

किस कोरटाइन को निलंबित किया जाता है?

आइए अपने कोड को देखें और क्या होता है:

// 1. this call starts a new coroutine (let's call it C1).
//    If there were code after it, it would be executed concurrently with
//    the body of this async
async {
    ...
    // 2. this is a regular function call
    val deferred = computation()
    // 4. because await() is suspendING, it suspends coroutine C1.
    //    This means that if we had a single thread in our dispatcher, 
    //    it would now be free to go execute C2
    // 7. once C2 completes, C1 is resumed with the result `true` of C2's async
    val result = deferred.await() 
    ...
    // 8. C1 can now keep going in the current thread until it gets 
    //    suspended again (or not)
}

fun computation(): Deferred<Boolean> {
    // 3. this async call starts a second coroutine (C2). Depending on the 
    //    dispatcher you're using, you may have one or more threads.
    // 3.a. If you have multiple threads, the block of this async could be
    //      executed in parallel of C1 in another thread. The control flow 
    //      of the current thread returns to the caller of computation().
    // 3.b. If you have only one thread, the block is sort of "queued" but 
    //      not executed right away, and the control flow returns to the 
    //      caller of computation(). (unless a special dispatcher or 
    //      coroutine start argument is used, but let's keep it simple).
    //    In both cases, we say that this block executes "concurrently"
    //    with C1.
    return async {
        // 5. this may now be executed
        true
        // 6. C2 is now completed, so the thread can go back to executing 
        //    another coroutine (e.g. C1 here)
    }
}

बाहरी asyncएक coroutine शुरू करता है। जब यह पुकारता है computation(), तो आंतरिक asyncएक दूसरा कोरटाइन शुरू करता है। फिर, कॉल बाहरी कॉरआउट await()के निष्पादन को निलंबित कर देता है , जब तक कि आंतरिक कॉरआउट का निष्पादन समाप्त नहीं हो जाता। async async

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

सस्पेंड का मतलब यह है कि जबकि बाहरी एसिंक्श कॉरटाइन इंतजार कर रहा है (इंतजार कर रहा है) आंतरिक गणना कॉरटीन खत्म होने के लिए, यह (बाहरी एसिंक्स कॉरआउट) आइडल (इसलिए नाम निलंबित) और थ्रेड पूल में थ्रेड लौटाता है, और जब बच्चे की गणना कॉरटीन खत्म होती है। , यह (बाहरी एसिंक्श कॉरआउट) जागता है, पूल से एक और धागा लेता है और जारी रहता है?

हाँ, ठीक है।

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


3
महान जवाब, मुझे याद है कि इस तरह की बुनियादी व्याख्या जब कोरटाइन की बात आती है।
बर्नार्डो

किसी अन्य भाषा में क्यों लागू नहीं किया गया है? या क्या मैं कुछ न कुछ भूल रहा हूं? मैं इतने लंबे समय के लिए उस समाधान के बारे में सोच रहा हूं, खुश है कि कोटलिन के पास है, लेकिन यह सुनिश्चित नहीं है कि टीएस या जंग में ऐसा कुछ क्यों है
PEZO

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

क्षमा करें, मेरी टिप्पणी स्पष्ट नहीं थी। मैं सस्पेंड कीवर्ड की बात कर रहा हूं। यह async के समान नहीं है।
PEZO

रोमन के वीडियो की ओर इशारा करने के लिए धन्यवाद। शुद्ध सोना।
डेनिसमाईन

8

मैंने पाया है कि समझने suspendका सबसे अच्छा तरीका thisकीवर्ड और coroutineContextसंपत्ति के बीच एक सादृश्य बनाना है ।

कोटलिन कार्यों को स्थानीय या वैश्विक घोषित किया जा सकता है। स्थानीय कार्यों में thisवैश्विक रूप से कीवर्ड तक पहुंच होती है ।

कोटलिन फ़ंक्शंस को suspendअवरुद्ध या घोषित किया जा सकता है । suspendकार्यों coroutineContextको रोकते समय जादुई रूप से संपत्ति तक पहुंच होती है ।

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

thisस्थानीय कार्यों के लिए कीवर्ड क्या करता है, coroutineContextसंपत्ति कार्यों के लिए क्या करती suspendहै: यह निष्पादन के वर्तमान संदर्भ तक पहुंच प्रदान करता है।

तो, आपको संपत्ति suspendतक पहुंच प्राप्त करने की आवश्यकता है coroutineContext- वर्तमान में निष्पादित कोरटाइन संदर्भ का उदाहरण


5

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

स्पष्ट होने के लिए, एक coroutine का उपयोग करके रोका जा सकता है suspend फ़ंक्शन है। इसकी जांच करने देता है:

Android में हम उदाहरण के लिए ऐसा कर सकते हैं:

var TAG = "myTAG:"
        fun myMethod() { // function A in image
            viewModelScope.launch(Dispatchers.Default) {
                for (i in 10..15) {
                    if (i == 10) { //on first iteration, we will completely FREEZE this coroutine (just for loop here gets 'suspended`)
                        println("$TAG im a tired coroutine - let someone else print the numbers async. i'll suspend until your done")
                        freezePleaseIAmDoingHeavyWork()
                    } else
                        println("$TAG $i")
                    }
            }

            //this area is not suspended, you can continue doing work
        }


        suspend fun freezePleaseIAmDoingHeavyWork() { // function B in image
            withContext(Dispatchers.Default) {
                async {
                    //pretend this is a big network call
                    for (i in 1..10) {
                        println("$TAG $i")
                        delay(1_000)//delay pauses coroutine, NOT the thread. use  Thread.sleep if you want to pause a thread. 
                    }
                    println("$TAG phwww finished printing those numbers async now im tired, thank you for freezing, you may resume")
                }
            }
        }

उपरोक्त कोड निम्नलिखित प्रिंट करता है:

I: myTAG: my coroutine is frozen but i can carry on to do other things

I: myTAG: im a tired coroutine - let someone else print the numbers async. i'll suspend until your done

I: myTAG: 1
I: myTAG: 2
I: myTAG: 3
I: myTAG: 4
I: myTAG: 5
I: myTAG: 6
I: myTAG: 7
I: myTAG: 8
I: myTAG: 9
I: myTAG: 10

I: myTAG: phwww finished printing those numbers async now im tired, thank you for freezing, you may resume

I: myTAG: 11
I: myTAG: 12
I: myTAG: 13
I: myTAG: 14
I: myTAG: 15

इस तरह काम करने की कल्पना करो:

यहां छवि विवरण दर्ज करें

तो आपके द्वारा लॉन्च किया गया वर्तमान फ़ंक्शन बंद नहीं होता है, बस एक कॉरटॉयइन सस्पेंड होता है जबकि यह जारी रहता है। निलंबित फ़ंक्शन चलाकर थ्रेड को रोक नहीं दिया गया है।

मुझे लगता है कि यह साइट आपको सीधे चीजों की मदद कर सकती है और मेरा संदर्भ है।

चलो कुछ शांत करते हैं और एक पुनरावृत्ति के बीच में हमारे निलंबन समारोह को फ्रीज करते हैं। हम इसे बाद में फिर से शुरू करेंगेonResume

नामक एक चर को स्टोर करें continuationऔर हम इसे हमारे लिए कोरटाइन्स कंटिन्यूएशन ऑब्जेक्ट के साथ लोड करेंगे:

var continuation: CancellableContinuation<String>? = null

suspend fun freezeHere() = suspendCancellableCoroutine<String> {
            continuation = it
        }

 fun unFreeze() {
            continuation?.resume("im resuming") {}
        }

अब, चलिए अपने निलंबित फ़ंक्शन पर लौटते हैं और इसे पुनरावृति के बीच में स्थिर करते हैं:

 suspend fun freezePleaseIAmDoingHeavyWork() {
        withContext(Dispatchers.Default) {
            async {
                //pretend this is a big network call
                for (i in 1..10) {
                    println("$TAG $i")
                    delay(1_000)
                    if(i == 3)
                        freezeHere() //dead pause, do not go any further
                }
            }
        }
    }

फिर कहीं और जैसे onResume (उदाहरण के लिए):

override fun onResume() {
        super.onResume()
        unFreeze()
    }

और लूप जारी रहेगा। यह जानने के लिए कि हम किसी भी बिंदु पर एक निलंबित समारोह को फ्रीज कर सकते हैं और कुछ समय बीत जाने के बाद इसे फिर से शुरू कर सकते हैं, यह बहुत साफ है। आप चैनलों में भी देख सकते हैं


4

जितने अच्छे उत्तर पहले से मौजूद हैं, मैं दूसरों के लिए एक सरल उदाहरण देना चाहूंगा।

रनबॉकिंग उपयोग मामला:

  • myMethod () suspendफ़ंक्शन है
  • runBlocking { }अवरुद्ध मार्ग में एक कोराउटिन शुरू करता है। यह समान है कि कैसे हम सामान्य थ्रेड्स को Threadवर्ग के साथ अवरुद्ध कर रहे थे और कुछ घटनाओं के बाद अवरुद्ध थ्रेड्स को सूचित कर रहे थे ।
  • runBlocking { }वर्तमान निष्पादन थ्रेड को ब्लॉक करता है , जब तक कि कोरटाइन (बीच में {}) पूरा नहीं हो जाता

     override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        Log.i(TAG,"Outer code started on Thread : " + Thread.currentThread().name);
        runBlocking {
            Log.d(TAG,"Inner code started  on Thread : " + Thread.currentThread().name + " making outer code suspend");
            myMethod();
        }
        Log.i(TAG,"Outer code resumed on Thread : " + Thread.currentThread().name);
    }
    
    private suspend fun myMethod() {
        withContext(Dispatchers.Default) {
        for(i in 1..5) {
            Log.d(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
        }
    }

यह आउटपुट:

I/TAG: Outer code started on Thread : main
D/TAG: Inner code started  on Thread : main making outer code suspend
// ---- main thread blocked here, it will wait until coroutine gets completed ----
D/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-2
// ---- main thread resumes as coroutine is completed ----
I/TAG: Outer code resumed on Thread : main

लॉन्च उपयोग मामला:

  • launch { } समवर्ती रूप से एक coroutine शुरू करता है।
  • इसका मतलब यह है कि जब हम लॉन्च को निर्दिष्ट करते हैं, तो एक coroutine workerधागे पर निष्पादन शुरू करता है।
  • workerधागा और बाहरी धागा (जिसमें से हमें बुलाया launch { }) दोनों समवर्ती चलाता है। आंतरिक रूप से, JVM प्रीमेप्टिव थ्रेडिंग का प्रदर्शन कर सकता है
  • जब हमें समानांतर में चलने के लिए कई कार्यों की आवश्यकता होती है, तो हम इसका उपयोग कर सकते हैं। scopesजो कोरटाइन के जीवनकाल को निर्दिष्ट करते हैं । यदि हम निर्दिष्ट करते हैं GlobalScope, तो कोरटाइन आवेदन के जीवनकाल समाप्त होने तक काम करेगा।

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        Log.i(TAG,"Outer code started on Thread : " + Thread.currentThread().name);
    
        GlobalScope.launch(Dispatchers.Default) {
            Log.d(TAG,"Inner code started  on Thread : " + Thread.currentThread().name + " making outer code suspend");
            myMethod();
        }
        Log.i(TAG,"Outer code resumed on Thread : " + Thread.currentThread().name);
    }
    
    private suspend fun myMethod() {
        withContext(Dispatchers.Default) {
            for(i in 1..5) {
                Log.d(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
            }
        }
    }

यह आउटपुट:

10806-10806/com.example.viewmodelapp I/TAG: Outer code started on Thread : main
10806-10806/com.example.viewmodelapp I/TAG: Outer code resumed on Thread : main
// ---- In this example, main had only 2 lines to execute. So, worker thread logs start only after main thread logs complete
// ---- In some cases, where main has more work to do, the worker thread logs get overlap with main thread logs
10806-10858/com.example.viewmodelapp D/TAG: Inner code started  on Thread : DefaultDispatcher-worker-1 making outer code suspend
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-1

async और प्रतीक्षारत उपयोग मामला:

  • जब हमारे पास करने के लिए कई कार्य हैं और वे दूसरे के पूरा होने पर निर्भर करते हैं, asyncऔर awaitइससे मदद मिलेगी।
  • उदाहरण के लिए, नीचे दिए गए कोड में, 2निलंबित कार्य myMethod () और myMethod2 () हैं। myMethod2()पूर्ण होने के बाद ही निष्पादित किया जाना चाहिए myMethod() या के myMethod2() परिणाम पर निर्भर करता है myMethod(), हम का उपयोग कर सकते हैं asyncऔरawait
  • asyncके समान समानांतर में एक coroutine शुरू करता है launch। लेकिन, यह समानांतर में एक और कोरटाइन शुरू करने से पहले एक कोरआउट के लिए प्रतीक्षा करने का एक तरीका प्रदान करता है।
  • इस तरह है await()asyncका एक उदाहरण देता है Deffered<T>Tहोगा Unitडिफ़ॉल्ट के लिए। जब हमें किसी भी काम asyncके पूरा होने की प्रतीक्षा करने की आवश्यकता होती है , तो हमें उसके उदाहरण .await()पर कॉल करना होगा । नीचे दिए गए उदाहरण की तरह, हमने कहा कि इसका अर्थ है कि निष्पादन पूर्ण होने तक निलंबित हो जाएगा। हम आउटपुट में इसका अवलोकन कर सकते हैं। पहले पूरा हो जाता है, जो कहता है । और फिर अगला शुरू होता है, जो कॉल करता हैDeffered<T>asyncinnerAsync.await()innerAsyncinnerAsyncmyMethod()async innerAsync2myMethod2()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        Log.i(TAG,"Outer code started on Thread : " + Thread.currentThread().name);
    
         job = GlobalScope.launch(Dispatchers.Default) {
             innerAsync = async {
                 Log.d(TAG, "Inner code started  on Thread : " + Thread.currentThread().name + " making outer code suspend");
                 myMethod();
             }
             innerAsync.await()
    
             innerAsync2 = async {
                 Log.w(TAG, "Inner code started  on Thread : " + Thread.currentThread().name + " making outer code suspend");
                 myMethod2();
             }
        }
    
        Log.i(TAG,"Outer code resumed on Thread : " + Thread.currentThread().name);
        }
    
    private suspend fun myMethod() {
        withContext(Dispatchers.Default) {
            for(i in 1..5) {
                Log.d(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
            }
        }
    }
    
    private suspend fun myMethod2() {
        withContext(Dispatchers.Default) {
            for(i in 1..10) {
                Log.w(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
            }
        }
    }

यह आउटपुट:

11814-11814/? I/TAG: Outer code started on Thread : main
11814-11814/? I/TAG: Outer code resumed on Thread : main
11814-11845/? D/TAG: Inner code started  on Thread : DefaultDispatcher-worker-2 making outer code suspend
11814-11845/? D/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-2
// ---- Due to await() call, innerAsync2 will start only after innerAsync gets completed
11814-11848/? W/TAG: Inner code started  on Thread : DefaultDispatcher-worker-4 making outer code suspend
11814-11848/? W/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 6 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 7 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 8 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 9 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 10 on Thread : DefaultDispatcher-worker-4
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.