Kotlin coroutines में लॉन्च / join और async / wait के बीच क्या अंतर है


जवाबों:


232
  • launchको आग लगाने और भूल जाने के लिए प्रयोग किया जाता है । यह एक नया सूत्र शुरू करने जैसा है। अंदर कोड तो launchअपवाद के साथ समाप्त, तो यह की तरह व्यवहार किया जाता है ध्यान में न आया एक सूत्र में अपवाद - आम तौर पर बैकएंड JVM अनुप्रयोगों में stderr करने के लिए मुद्रित और Android एप्लिकेशन दुर्घटनाओं। joinका उपयोग लॉन्च किए गए कोरआउट के पूरा होने की प्रतीक्षा करने के लिए किया जाता है और यह इसके अपवाद का प्रचार नहीं करता है। हालाँकि, एक दुर्घटनाग्रस्त बच्चा कोरटाइन अपने माता-पिता को इसी अपवाद के साथ रद्द कर देता है।

  • asyncएक कॉरआउट शुरू करने के लिए उपयोग किया जाता है जो कुछ परिणाम की गणना करता है । परिणाम एक उदाहरण द्वारा दर्शाया गया है Deferredऔर आपको इस पर उपयोग करना चाहिएawaitasyncकोड के अंदर एक अनियोजित अपवाद परिणाम के अंदर संग्रहीत किया जाता है Deferredऔर कहीं और वितरित नहीं किया जाता है, यह तब तक चुपचाप गिरा दिया जाएगा जब तक कि संसाधित नहीं किया जाता है। तुम जरूरी नहीं है कि आप asout के साथ शुरू कर दिया है कि coroutine के बारे में भूल जाओ


1
एंड्रॉइड में नेटवर्क कॉल के लिए सही कॉइनआउट बिल्डर Async है?
फ़राज़

सही कोरटाइन बिल्डर इस बात पर निर्भर करता है कि आप क्या हासिल करने की कोशिश कर रहे हैं
रोमन एलिसारोव

9
क्या आप "आप एस्से के साथ शुरू की गई कोरटाइन के बारे में नहीं भूल सकते" पर विस्तार से बता सकते हैं? क्या ऐसे गोचर्स हैं, जो उदाहरण के लिए उम्मीद नहीं करेंगे?
लुइस

2
"Async कोड के अंदर एक अनियोजित अपवाद परिणामी Deferred के अंदर संग्रहीत किया जाता है और इसे कहीं और वितरित नहीं किया जाता है, इसे संसाधित किए जाने तक चुपचाप हटा दिया जाएगा।"
रोमन एलिसारोव

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

77

मुझे यह मार्गदर्शिका https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md उपयोगी लगती है। मैं आवश्यक भागों का उद्धरण दूंगा

🦄 coroutine

मूल रूप से, कोरआउट हल्के वजन के धागे होते हैं।

तो आप कोरटाइन के बारे में सोच सकते हैं जो एक बहुत ही कुशल तरीके से धागे का प्रबंधन करता है।

🐤 लॉन्च

fun main(args: Array<String>) {
    launch { // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

तो launchएक बैकग्राउंड थ्रेड शुरू करता है, कुछ करता है, और तुरंत एक टोकन लौटाता है Job। आप joinइस पर कॉल कर सकते हैं Jobजब तक कि यह launchधागा पूरा न हो जाए

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch { // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // wait until child coroutine completes
}

🦆 async

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

तो asyncएक बैकग्राउंड थ्रेड शुरू करता है, कुछ करता है, और तुरंत एक टोकन लौटाता है Deferred

fun main(args: Array<String>) = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

आप इसका अंतिम परिणाम प्राप्त करने के लिए एक आस्थगित मूल्य पर .wait () का उपयोग कर सकते हैं, लेकिन आस्थगित भी एक नौकरी है, इसलिए यदि आवश्यक हो तो आप इसे रद्द कर सकते हैं।

तो Deferredवास्तव में एक है JobHttps://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html देखें

interface Deferred<out T> : Job (source)

🦋 async डिफ़ॉल्ट रूप से उत्सुक है

CoroutineStart.LAZY के मान के साथ एक वैकल्पिक प्रारंभ पैरामीटर का उपयोग करके async के लिए एक आलस्य विकल्प है। यह केवल तब शुरू होता है जब इसके परिणाम में कुछ प्रतीक्षा की आवश्यकता होती है या यदि कोई प्रारंभ कार्य होता है।


11

launchऔर asyncनए कॉरआउट शुरू करने के लिए उपयोग किया जाता है। लेकिन, वे उन्हें अलग तरीके से निष्पादित करते हैं।

मैं बहुत बुनियादी उदाहरण दिखाना चाहूंगा जो आपको अंतर को बहुत आसानी से समझने में मदद करेगा

  1. प्रक्षेपण
    class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnCount.setOnClickListener {
            pgBar.visibility = View.VISIBLE
            CoroutineScope(Dispatchers.Main).launch {
                val currentMillis = System.currentTimeMillis()
                val retVal1 = downloadTask1()
                val retVal2 = downloadTask2()
                val retVal3 = downloadTask3()
                Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1}, ${retVal2}, ${retVal3} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
                pgBar.visibility = View.GONE
            }
        }

    // Task 1 will take 5 seconds to complete download
    private suspend fun downloadTask1() : String {
        kotlinx.coroutines.delay(5000);
        return "Complete";
    }

    // Task 1 will take 8 seconds to complete download    
    private suspend fun downloadTask2() : Int {
        kotlinx.coroutines.delay(8000);
        return 100;
    }

    // Task 1 will take 5 seconds to complete download
    private suspend fun downloadTask3() : Float {
        kotlinx.coroutines.delay(5000);
        return 4.0f;
    }
}

इस उदाहरण में, मेरा कोड btnCountबटन के क्लिक पर 3 डेटा डाउनलोड कर रहा है और pgBarसभी डाउनलोड पूरा होने तक प्रगति बार दिखा रहा है । 3 suspendकार्य हैं downloadTask1(), downloadTask2()और downloadTask3()जो डेटा डाउनलोड करते हैं। इसे अनुकरण करने के लिए, मैंने delay()इन कार्यों में उपयोग किया है। ये कार्य क्रमशः प्रतीक्षा करते हैं 5 seconds, 8 secondsऔर 5 secondsक्रमशः।

जैसा कि हमने launchइन निलंबित कार्यों को शुरू करने के लिए उपयोग किया है , launchउन्हें क्रमिक रूप से (एक-एक करके) निष्पादित करेगा । इसका मतलब है कि, पूरा downloadTask2()होने के बाद शुरू होगा downloadTask1()और पूरा होने के बाद downloadTask3()ही शुरू होगा downloadTask2()

आउटपुट स्क्रीनशॉट के रूप में Toast, सभी 3 डाउनलोड पूरा करने के लिए कुल निष्पादन समय 5 सेकंड + 8 सेकंड + 5 सेकंड = 18 सेकंड के साथ होगाlaunch

उदाहरण लॉन्च करें

  1. async

जैसा कि हमने देखा कि सभी 3 कार्यों के लिए launchनिष्पादन होता sequentiallyहै। सभी कार्यों को पूरा करने का समय था 18 seconds

यदि वे कार्य स्वतंत्र हैं और यदि उन्हें अन्य कार्य के संगणना परिणाम की आवश्यकता नहीं है, तो हम उन्हें चला सकते हैं concurrently। वे एक ही समय में शुरू होते हैं और पृष्ठभूमि में समवर्ती रूप से चलते हैं। इसके साथ किया जा सकता है async

asyncDeffered<T>प्रकार का एक रिटर्न देता है , जहां Tडेटा का प्रकार हमारे निलंबन फ़ंक्शन को रिटर्न करता है। उदाहरण के लिए,

  • downloadTask1()Deferred<String>स्ट्रिंग के रूप में वापस आ जाएगा समारोह का प्रकार है
  • downloadTask2()Deferred<Int>Int के रूप में वापसी होगी फ़ंक्शन का प्रकार
  • downloadTask3()वापसी होगी Deferred<Float>फ्लोट के रूप में समारोह की वापसी प्रकार है

asyncप्रकार Deferred<T>में लौटे मूल्य को प्राप्त करने के लिए हम प्रकार से वापसी ऑब्जेक्ट का उपयोग कर सकते हैं T। जिसे await()कॉल के साथ किया जा सकता है । उदाहरण के लिए नीचे दिए गए कोड की जाँच करें

        btnCount.setOnClickListener {
        pgBar.visibility = View.VISIBLE

        CoroutineScope(Dispatchers.Main).launch {
            val currentMillis = System.currentTimeMillis()
            val retVal1 = async(Dispatchers.IO) { downloadTask1() }
            val retVal2 = async(Dispatchers.IO) { downloadTask2() }
            val retVal3 = async(Dispatchers.IO) { downloadTask3() }

            Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1.await()}, ${retVal2.await()}, ${retVal3.await()} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
            pgBar.visibility = View.GONE
        }

इस तरह, हमने सभी 3 कार्यों को समवर्ती रूप से शुरू किया है। इसलिए, मेरे पूर्ण निष्पादन का समय केवल वही होगा 8 secondsजो समय के लिए है downloadTask2()क्योंकि यह सभी 3 कार्यों में से सबसे बड़ा है। आप इसे निम्न स्क्रीनशॉट में देख सकते हैंToast message

उदाहरण का इंतजार करें


1
कि उल्लेख के लिए धन्यवाद launchके लिए है अनुक्रमिक funs, जबकि asyncके लिए समवर्ती
Akbolat एसएसएस

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

1
यह उत्तर सही नहीं है, क्योंकि एस्सेन की तुलना लॉन्च के बजाय सीधे निलंबित कार्यों के साथ की जाती है। सस्पेंड फ़ंक्शन को सीधे उदाहरण में कॉल करने के बजाय, यदि आप लॉन्च कहते हैं (Dispatchers.IO) {downloadTask1 ()} तो आप देखेंगे कि दोनों को समवर्ती रूप से निष्पादित किया गया है, क्रमिक रूप से नहीं , आप आउटपुट प्राप्त करने में सक्षम नहीं होंगे, लेकिन आप देखेंगे कि यह है अनुक्रमिक नहीं। इसके अलावा, यदि आप deferred.await () और deferred.await () कॉल को अलग-अलग नहीं करते हैं, तो आप देखेंगे कि async अनुक्रमिक है।
थ्रेशियन

2
-1 यह सिर्फ सादा गलत है। दोनों launchऔर asyncनए coroutines शुरू कर देंगे। आप एक एकल कॉरआउट की तुलना कर रहे हैं, जिसमें 3 बच्चों के साथ एक भी कॉरआउट नहीं है। आप प्रत्येक asyncइनवोकेशन launchको बदल सकते हैं और समवर्ती के संबंध में कुछ भी नहीं बदलेगा।
मोइरा

इस उत्तर में विलक्षण शोर जटिलता को जोड़ रहा है जो सह-दिनचर्या विषय के बाहर है।
१३:५३ पर truthadjustr

6
  1. दोनों coroutine बिल्डरों अर्थात् लॉन्च और async मूल रूप से प्रकार के रिसीवर के साथ lambdas हैं CoroutineScope जिसका अर्थ है कि उनके आंतरिक ब्लॉक को एक निलंबित फ़ंक्शन के रूप में संकलित किया गया है, इसलिए वे दोनों एक एसिंक्रोनस मोड में चलते हैं और वे दोनों अपने ब्लॉक को क्रमिक रूप से निष्पादित करेंगे।

  2. लॉन्च और एसिंक्स के बीच अंतर यह है कि वे दो अलग-अलग संभावनाओं को सक्षम करते हैं। लॉन्च बिल्डर एक नौकरी लौटाता है, लेकिन एसिंक्स फ़ंक्शन एक आस्थगित ऑब्जेक्ट लौटाएगा। आप किसी ब्लॉक को निष्पादित करने के लिए लॉन्च का उपयोग कर सकते हैं, जिसे आप किसी भी लौटाए गए मूल्य की अपेक्षा नहीं करते हैं, अर्थात डेटाबेस में लिखना या किसी फ़ाइल को सहेजना या किसी चीज़ को संसाधित करना जो मूल रूप से इसके दुष्प्रभाव के लिए कहा जाता है। दूसरी ओर async जो एक डिफर्ड को वापस करता है जैसा कि मैंने पहले ही कहा था कि इसके ब्लॉक के निष्पादन से एक उपयोगी मूल्य मिलता है, एक ऑब्जेक्ट जो आपके डेटा को लपेटता है, इसलिए आप इसे मुख्य रूप से इसके परिणाम के लिए उपयोग कर सकते हैं लेकिन संभवतः इसके साइड इफेक्ट के लिए भी। NB: आप आस्थगित छीन सकते हैं और फ़ंक्शन प्रतीक्षा का उपयोग करके इसका मूल्य प्राप्त कर सकते हैं, जो आपके बयानों के निष्पादन को तब तक रोक देगा जब तक कि कोई मूल्य वापस नहीं किया जाता है या एक अपवाद नहीं फेंका जाता है!

  3. दोनों coroutine बिल्डर (लॉन्च और Async) रद्द करने योग्य हैं।

  4. कुछ और ?: लॉन्च के साथ हां यदि कोई अपवाद इसके ब्लॉक के भीतर फेंक दिया जाता है, तो कोरटाइन स्वचालित रूप से रद्द कर दिया जाता है और अपवादों को वितरित किया जाता है। दूसरी ओर, अगर ऐसा होता है तो एसिंक्स के साथ अपवाद को आगे प्रचारित नहीं किया जाता है और उसे लौटाए गए डिफरेंट ऑब्जेक्ट के भीतर पकड़ा / संभाला जाना चाहिए।

  5. अधिक coroutines पर https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html https://www.codementor.io/blog/kotlin-coroutines-6n53b8cbn1


1
इस टिप्पणी के लिए धन्यवाद। इसने सूत्र के सभी बिंदुओं को एकत्र किया। मैं जोड़ता हूं कि सभी लॉन्च रद्द नहीं किए गए हैं जैसे परमाणु कभी भी रद्द नहीं किए जा सकते।
P2lem8dev

4

लॉन्च एक नौकरी देता है

async एक परिणाम देता है (आस्थगित नौकरी)

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

कुछ परिणामों की गणना करने के लिए async का उपयोग किया जाता है। यह एक coroutine बनाता है और Deferred के कार्यान्वयन के रूप में अपना भविष्य परिणाम देता है। जब परिणामी आस्थगित रद्द कर दिया जाता है, तो चल रहे कोरआउट को रद्द कर दिया जाता है।

एक एसिंक्स विधि पर विचार करें जो एक स्ट्रिंग मान लौटाता है। यदि एस्किंट विधि का उपयोग किए बिना प्रतीक्षा की जाती है, तो यह आस्थगित स्ट्रिंग लौटाएगा लेकिन यदि प्रतीक्षा का उपयोग किया जाता है, तो आपको परिणाम के रूप में एक स्ट्रिंग मिलेगी

Async और लॉन्च के बीच महत्वपूर्ण अंतर। जब आप जॉब नहीं करते, तब तक आपकी Toutout खत्म होने के बाद Deferred टाइप T का एक विशेष मान देता है।


0

Async बनाम लॉन्च Async बनाम लॉन्च डिफ इमेज

लॉन्च / async कोई परिणाम नहीं

  • परिणाम की आवश्यकता न होने पर उपयोग करें,
  • जहाँ कहा जाता है, उस कोड को ब्लॉक न करें
  • समानांतर में चलें

परिणाम के लिए async

  • जब आपको परिणाम की प्रतीक्षा करने की आवश्यकता होती है और दक्षता के लिए समानांतर में चल सकता है
  • उस कोड को ब्लॉक करें जहां कहा जाता है
  • समानांतर में चलाना
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.