कोटलिन कोरटाइन "गारंटी से पहले" होता है?


10

क्या कोटलिन कॉरआउट्स गारंटी प्रदान करता है?

उदाहरण के लिए, क्या mutableVarइस मामले में अन्य संभावित सूत्र पर (संभावित रूप से) पर लिखने और बाद में पढ़ने के बीच "होने वाली-पहले" गारंटी है :

suspend fun doSomething() {
    var mutableVar = 0
    withContext(Dispatchers.IO) {
        mutableVar = 1
    }
    System.out.println("value: $mutableVar")
}

संपादित करें:

शायद अतिरिक्त उदाहरण प्रश्न को बेहतर ढंग से स्पष्ट करेगा क्योंकि यह अधिक कोटलिन-ईश (उत्परिवर्तन को छोड़कर) है। क्या यह कोड थ्रेड सुरक्षित है:

suspend fun doSomething() {
    var data = withContext(Dispatchers.IO) {
        Data(1)
    }
    System.out.println("value: ${data.data}")
}

private data class Data(var data: Int)

ध्यान दें कि JVM Kotlin पर चलने पर जावा के समान मेमोरी मॉडल का उपयोग किया जाता है।
slaw

1
@ स्लाव, मुझे पता है कि। हालांकि, हुड के नीचे बहुत सारा जादू चल रहा है। इसलिए, मैं यह समझना चाहता हूं कि क्या कोई ऐसा होता है-इससे पहले कि मुझे कोरटाइन से गारंटी मिले, या यह सब मुझ पर है।
वासिली

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

... और दोनों उदाहरणों से पहले "प्रोग्राम ऑर्डर" पहलू होता है-पहले, सबसे तुच्छ। मैं यहां कोरटाइन्स के स्तर पर बोल रहा हूं, न कि अंतर्निहित JVM। तो मूल रूप से, आप पूछ रहे हैं कि क्या कोटलिन कोरटाइन इतने गंभीर रूप से टूटे हुए हैं कि वे प्रोग्राम ऑर्डर होने से पहले भी प्रदान नहीं करते हैं।
मार्को टोपोलनिक

1
@MarkoTopolnik, मुझे सही करें यदि मैं गलत हूं, लेकिन JLS केवल एक ही थ्रेड पर निष्पादन के लिए "प्रोग्राम ऑर्डर होता है-पहले" की गारंटी देता है। अब, कोरटाइन के साथ, भले ही कोड अनुक्रमिक दिखता है, व्यवहार में कुछ मशीनरी हैं जो इसे अलग-अलग थ्रेड्स में लोड करती हैं। मैं समझता हूं कि आपकी बात "यह एक ऐसी बुनियादी गारंटी है कि मैं अपना समय इसे जाँचने में व्यर्थ नहीं करूंगा" (दूसरी टिप्पणी से), लेकिन मैंने इस सवाल का कड़ा जवाब दिया। मुझे पूरा यकीन है कि मेरे द्वारा लिखे गए उदाहरण थ्रेड सुरक्षित हैं, लेकिन मैं समझना चाहता हूं कि क्यों।
वासिली

जवाबों:


6

आपके द्वारा लिखे गए कोड में साझा स्थिति के लिए तीन एक्सेस हैं:

var mutableVar = 0                        // access 1, init
withContext(Dispatchers.IO) {
    mutableVar = 1                        // access 2, write
}
System.out.println("value: $mutableVar")  // access 3, read

तीन पहुंचों को सख्ती से क्रमबद्ध रूप से आदेश दिया गया है, जिनके बीच कोई संगामिति नहीं है, और आप निश्चिंत हो सकते हैं कि कोटलिन के बुनियादी ढांचे में थ्रेड पूल में हाथ डालने और अपने कॉलिंग कॉरटीन में वापस जाने से पहले होने वाली बढ़त का ध्यान रखा जाता है IO

यहाँ एक समतुल्य उदाहरण दिया गया है जो शायद और अधिक ठोस हो

launch(Dispatchers.Default) {
    var mutableVar = 0             // 1
    delay(1)
    mutableVar = 1                 // 2
    delay(1)
    println("value: $mutableVar")  // 3
}

चूंकि delayएक संदिग्ध कार्य है, और जब से हम Defaultडिस्पैचर का उपयोग कर रहे हैं जो थ्रेड पूल द्वारा समर्थित है, लाइनें 1, 2 और 3 प्रत्येक एक अलग थ्रेड पर निष्पादित हो सकती हैं। इसलिए होने से पहले आपका प्रश्न इस उदाहरण के लिए समान रूप से लागू होता है। दूसरी ओर, इस मामले में यह (मुझे उम्मीद है) पूरी तरह से स्पष्ट होगा कि इस कोड का व्यवहार अनुक्रमिक निष्पादन के सिद्धांतों के अनुरूप है।


1
धन्यवाद। यह वास्तव में "आराम का आश्वासन" के बाद का हिस्सा है जिसने मुझे यह सवाल पूछने के लिए प्रेरित किया। क्या डॉक्स के लिए कोई लिंक हैं जो मैं पढ़ सकता था? वैकल्पिक रूप से, स्रोत कोड के लिंक जहां ऐसा होता है-पहले किनारे स्थापित किया जाता है वह भी बहुत मदद करेगा (शामिल हों, सिंक्रनाइज़ेशन, या किसी अन्य विधि)।
वासिली

1
यह ऐसी बुनियादी गारंटी है कि मैं अपना समय बर्बाद नहीं करूंगा। हुड के नीचे यह उबलता है executorService.submit()और कार्य के पूरा होने पर इंतजार करने का कुछ विशिष्ट तंत्र है (एक CompletableFutureया कुछ इसी तरह पूरा करना )। Kotlin coroutines के दृष्टिकोण से, यहाँ कोई भी निर्णायक नहीं है।
मार्को टोपोलनिक

1
आप अपने प्रश्न के बारे में सोच कर पूछ सकते हैं कि "क्या ओएस किसी थ्रेड को सस्पेंड करने से पहले और फिर इसे किसी अन्य कोर पर फिर से शुरू करने की गारंटी देता है?" थ्रेड्स कोरटाइन्स के लिए हैं जो CPU कोर थ्रेड्स के लिए हैं।
मार्को टोपोलनिक

1
आपके व्याख्या के लिये धन्यवाद। हालांकि, मैंने यह सवाल पूछा कि यह क्यों काम करता है। मैं आपकी बात देख रहा हूं, लेकिन, अब तक, यह वह कठोर जवाब नहीं है जिसकी मुझे तलाश है।
वासिली

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

3

कोटलिन में कोराटाइन प्रदान करता है गारंटी से पहले होता है।

नियम है: एक coroutine अंदर, कोड से पहले एक निलंबित करने के लिए समारोह कॉल से पहले होता है कोड के बाद निलंबित कॉल।

आपको कोरटाइन के बारे में सोचना चाहिए जैसे कि वे नियमित धागे थे:

भले ही कोटलिन में एक कोरआउट कई थ्रेड्स पर निष्पादित कर सकता है, लेकिन यह केवल उत्परिवर्तनीय स्थिति के दृष्टिकोण से एक धागे की तरह है। एक ही कॉरआउट में कोई दो क्रियाएं समवर्ती नहीं हो सकती हैं।

स्रोत: https://proandroiddev.com/what-is-concurrent-access-to-mutable-state-f386e5cb8292

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

Https://youtrack.jetbrains.com/issue/KT-15514 देखें


नियम यह है, वास्तव में: सस्पेंड फ़ंक्शन कॉल से पहले कोड होता है- सस्पेंड फ़ंक्शन के अंदर कोड से पहले , होता है- सस्पेंड कॉल के बाद कोड से पहले । यह, बदले में, "कोड के कार्यक्रम क्रम भी कोड के होने से पहले का आदेश है" के लिए सामान्यीकृत किया जा सकता है । उस कथन में संदिग्ध कार्यों के लिए कुछ विशेष की अनुपस्थिति पर ध्यान दें।
मार्को टोपोलनिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.