Gelen kotlinx.coroutines
kütüphaneye ya kullanarak yeni eşyordam başlayabilirsiniz launch
(ile join
) ya da async
(birlikte await
). Onların arasındaki fark ne?
Gelen kotlinx.coroutines
kütüphaneye ya kullanarak yeni eşyordam başlayabilirsiniz launch
(ile join
) ya da async
(birlikte await
). Onların arasındaki fark ne?
Yanıtlar:
launch
ateş ve coroutine unutmak için kullanılır . Yeni bir konu açmak gibidir. İçindeki kod launch
istisna ile sonlanırsa , bir iş parçacığında yakalanmamış istisna gibi davranılır - genellikle arka uç JVM uygulamalarında stderr'a yazdırılır ve Android uygulamalarını kilitler. join
başlatılan programın tamamlanmasını beklemek için kullanılır ve istisnasını yaymaz. Ancak, çökmüş bir çocuk coutini, ebeveynini de buna karşılık gelen istisna ile iptal eder.
async
bazı sonuçları hesaplayan bir programın başlatılması için kullanılır . Sonuç bir örneği ile temsil edilir Deferred
ve üzerinde kullanmanız gerekirawait
. async
Kodun içinde yakalanmamış bir istisna , sonuçta saklanır Deferred
ve başka bir yere teslim edilmez, işlenmedikçe sessizce düşecektir. Zaman uyumsuzluğuyla başladığınız koroutini unutmamalısınız .
Bu kılavuzu https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md faydalı buluyorum . Önemli parçaları teklif edeceğim
🦄 eşyordam
Esasen, koroutinler hafif ipliklerdir.
Böylece koroutini, ipliği çok verimli bir şekilde yöneten bir şey olarak düşünebilirsiniz.
🐤 başlat
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
}
Böylece launch
bir arka plan iş parçacığı başlar, bir şey yapar ve hemen bir jeton olarak döner Job
. Arayabilirsinjoin
bu konuda Job
bu kadar engellemek için launch
iplik tamamlanıncaya
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
}
🦆 zaman uyumsuz
Kavramsal olarak, asenkron tıpkı lansman gibidir. Diğer tüm koroutinlerle aynı anda çalışan hafif bir iplik olan ayrı bir koroutin başlatır. Fark, lansmanın bir İş döndürdüğü ve sonuçta herhangi bir değer taşımadığı, async ise Ertelenmiş - daha sonra bir sonuç verme vaadini temsil eden hafif, bloke olmayan bir gelecek döndürür.
Böylece async
bir arka plan iş parçacığı başlar, bir şey yapar ve hemen bir jeton olarak döner 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")
}
Son sonucunu almak için ertelenmiş bir değerde .await () kullanabilirsiniz, ancak Ertelenmiş de bir İştir, bu nedenle gerekirse iptal edebilirsiniz.
Yani Deferred
aslında bir olduğunu Job
. Görmek Https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
interface Deferred<out T> : Job (source)
🦋 uyumsuz varsayılan olarak istekli
CoroutineStart.LAZY değerine sahip isteğe bağlı bir başlangıç parametresi kullanarak zaman uyumsuzluk için tembellik seçeneği vardır. Koroutine ancak sonucu bazılarının beklemesi gerektiğinde veya bir başlatma fonksiyonu çağrıldığında başlar.
launch
ve async
yeni ortak programlar başlatmak için kullanılır. Ancak, onları farklı bir şekilde yürütürler.
Farkı kolayca anlamanıza yardımcı olacak çok temel bir örnek göstermek istiyorum
- başlatmak
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;
}
}
Bu örnekte, kodum btnCount
düğmeyi tıkladığınızda 3 veri indiriyor ve pgBar
tüm indirme tamamlanana kadar ilerleme çubuğunu gösteriyor . 3 Var suspend
fonksiyonlar downloadTask1()
, downloadTask2()
ve downloadTask3()
veri indirir. Benzetmek için delay()
bu işlevlerde kullandım. Bu işlevler bekler 5 seconds
, 8 seconds
ve5 seconds
sırasıyla.
launch
Bu askıya alma işlevlerini başlatmak için kullandığımız için, launch
bunları sırayla (tek tek) yürütür . Ki bu araçlar downloadTask2()
sonra başlayacak downloadTask1()
tamamlanmış olur ve downloadTask3()
sonra başlayacakdownloadTask2()
.
Çıkış ekran gibi Toast
, toplam uygulama süresi 3 yükle yol açacak tamamlamak için 5 saniye + 8 saniye + 5 saniye = 18 saniye ilelaunch
- zaman uyumsuz
Gördüğümüz gibi o launch
yürütülmesine yapan sequentially
3 görevler için. Tüm görevleri tamamlamanın zamanı geldi 18 seconds
.
Bu görevler bağımsızsa ve başka bir görevin hesaplama sonucuna ihtiyaç duymazlarsa, onları çalıştırabiliriz concurrently
. Aynı anda başlayıp arka planda eşzamanlı olarak çalışırlardı. Bu ile yapılabilir async
.
async
Deffered<T>
tür örneğini döndürür ; burada T
askıya alma işlevimizin döndürdüğü veri türüdür. Örneğin,
downloadTask1()
dönecekti Deferred<String>
dize olarak fonksiyonun dönüş türüdürdownloadTask2()
dönecekti Deferred<Int>
Int olarak fonksiyonun dönüş türüdürdownloadTask3()
dönecekti Deferred<Float>
Float olarak fonksiyonun dönüş türüdürTürden döndürülen değeri almak için async
türden dönüş nesnesini kullanabiliriz . Bu çağrı ile yapılabilir . Örneğin aşağıdaki kodu kontrol edinDeferred<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
}
Bu şekilde, 3 görevin hepsini aynı anda başlattık. Yani, toplam yürütme sürem sadece 3 görevden en büyüğü 8 seconds
olduğu zaman olacak downloadTask2()
. Bunu aşağıdaki ekran görüntüsünde görebilirsiniz.Toast message
launch
içindir sıralı , eğlenceler sırasında async
için eşzamanlı
launch
ve async
yeni coroutines başlayacak. Hiçbir çocuğu olmayan tek bir koroutini 3 çocuğu olan tek bir koroutinin karşılaştırması yapıyorsunuz. Her bir async
çağrıyı launch
değiştirebilirsiniz ve eşzamanlılık konusunda kesinlikle hiçbir şey değişmez.
her iki birlikte oluşturucu, lansman ve eşzamansız olarak temelde CoroutineScope tipi alıcıya sahip lambdaslardır, bu da iç bloklarının bir askıya alma işlevi olarak derlendiği anlamına gelir, böylece her ikisi de eşzamansız modda çalışır ve her ikisi de bloklarını sırayla yürütür.
Başlatma ve zaman uyumsuzluk arasındaki fark, iki farklı olasılık sağlamalarıdır. Başlatma oluşturucusu bir İş döndürür, ancak zaman uyumsuz işlev Ertelenmiş bir nesne döndürür. Herhangi bir döndürülen değeri beklemediğiniz bir bloğu yürütmek için başlat'ı kullanabilirsiniz, yani bir veritabanına yazmak veya bir dosyayı kaydetmek veya temel olarak yan etkisi için çağrılan bir şeyi işlemek. Öte yandan, daha önce de belirttiğim gibi bir Ertelenmiş döndüren asenkron, bloğunun yürütülmesinden, verilerinizi saran bir nesne olan yararlı bir değer döndürür, böylece esas olarak sonucu için ama muhtemelen yan etkisi için de kullanabilirsiniz. Not: ertelenebilir ve değerini bir değer döndürülünceye veya bir istisna atılana kadar ifadelerinizin yürütülmesini engelleyecek olan işlev bekliyor işlevini kullanarak alabilirsiniz!
her iki program oluşturucu da (başlatma ve zaman uyumsuz) iptal edilebilir.
başka bir şey var mı ?: bloğuna bir istisna atılırsa, koroutin otomatik olarak iptal edilir ve istisnalar verilir. Öte yandan, bu zaman uyumsuzluk ile gerçekleşirse, istisna daha fazla yayılmaz ve döndürülen Ertelenmiş nesne içinde yakalanmalı / ele alınmalıdır.
coroutines hakkında daha fazla bilgi https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html https://www.codementor.io/blog/kotlin-coroutines-6n53p8cbn1
başlatmak bir iş döndürür
zaman uyumsuz bir sonuç döndürür (ertelenmiş iş)
join ile başlatmak, iş bitene kadar beklemek için kullanılır. bu arada, mevcut iş parçacığını (başka bir coroutine yürütmek gibi) diğer işleri yapmak için serbest bırakarak coroutine call join () öğesini askıya alır.
zaman uyumsuz bazı sonuçları hesaplamak için kullanılır. Bir koroutin oluşturur ve gelecekteki sonucunu Ertelenmiş bir uygulama olarak döndürür. Ortaya çıkan erteleme, ertelenen erteleme iptal edildiğinde iptal edilir.
Bir dize değeri döndüren bir zaman uyumsuz yöntem düşünün. Async yöntemi beklemeden kullanılırsa, Ertelenmiş bir dize döndürür, ancak beklenirse sonuç olarak bir dize alırsınız
Zaman uyumsuzluk ve başlatma arasındaki temel fark. Ertelenmiş, Coroutine'nizin yürütülmesi bittikten sonra belirli bir T türü değeri döndürür, ancak Job bunu yapmaz.
Async vs Launch Async vs Launch Diff Görüntü
başlat / async sonuç yok
sonuç için zaman uyumsuz