Di kotlinx.coroutines
perpustakaan Anda dapat memulai coroutine baru menggunakan launch
(dengan join
) atau async
(dengan await
). Apa perbedaan di antara mereka?
Di kotlinx.coroutines
perpustakaan Anda dapat memulai coroutine baru menggunakan launch
(dengan join
) atau async
(dengan await
). Apa perbedaan di antara mereka?
Jawaban:
launch
digunakan untuk menembak dan melupakan coroutine . Ini seperti memulai utas baru. Jika kode di dalam launch
terminal berakhir dengan pengecualian, maka kode tersebut diperlakukan seperti pengecualian yang tidak tertangkap di utas - biasanya dicetak ke stderr di aplikasi JVM backend dan aplikasi Android rusak. join
digunakan untuk menunggu penyelesaian coroutine yang diluncurkan dan tidak menyebarkan pengecualiannya. Namun, coroutine anak yang crash membatalkan induknya dengan pengecualian yang sesuai juga.
async
digunakan untuk memulai coroutine yang menghitung beberapa hasil . Hasilnya diwakili oleh instance Deferred
dan Anda harus menggunakannya await
. Pengecualian tanpa tertangkap di dalam async
kode disimpan di dalam hasil Deferred
dan tidak dikirim di tempat lain, itu akan diam-diam dijatuhkan kecuali diproses. Anda TIDAK HARUS melupakan coroutine yang sudah Anda mulai dengan async .
Saya menemukan panduan ini https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md berguna. Saya akan mengutip bagian-bagian penting
🦄 coroutine
Intinya, coroutine adalah benang yang ringan.
Jadi Anda bisa menganggap coroutine sebagai sesuatu yang mengelola thread dengan cara yang sangat efisien.
🐤 diluncurkan
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
}
Jadi mulailah launch
utas latar belakang, lakukan sesuatu, dan kembalikan token segera sebagai Job
. Anda dapat memanggil join
ini Job
untuk memblokir sampai launch
utas ini selesai
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
Secara konseptual, async seperti peluncuran. Ini memulai coroutine terpisah yang merupakan benang ringan yang bekerja bersamaan dengan semua coroutine lainnya. Perbedaannya adalah bahwa peluncuran mengembalikan suatu Pekerjaan dan tidak membawa nilai yang dihasilkan, sementara async mengembalikan yang Ditangguhkan - masa depan ringan tanpa pemblokiran yang mewakili janji untuk memberikan hasil nanti.
Jadi mulailah async
utas latar belakang, lakukan sesuatu, dan kembalikan token segera sebagai 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")
}
Anda dapat menggunakan .await () pada nilai yang ditangguhkan untuk mendapatkan hasil akhirnya, tetapi Ditangguhkan juga merupakan Pekerjaan, sehingga Anda dapat membatalkannya jika diperlukan.
Jadi Deferred
sebenarnya a Job
. Lihat https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
interface Deferred<out T> : Job (source)
🦋 async sangat ingin secara default
Ada opsi kemalasan untuk async menggunakan parameter awal opsional dengan nilai CoroutineStart.LAZY. Itu mulai coroutine hanya ketika hasilnya diperlukan oleh beberapa menunggu atau jika fungsi mulai dipanggil.
launch
dan async
digunakan untuk memulai coroutine baru. Tapi, mereka mengeksekusinya dengan cara yang berbeda.
Saya ingin menunjukkan contoh yang sangat mendasar yang akan membantu Anda memahami perbedaan dengan sangat mudah
- meluncurkan
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;
}
}
Dalam contoh ini, kode saya mengunduh 3 data dengan mengklik btnCount
tombol dan menampilkan pgBar
bilah kemajuan hingga semua unduhan selesai. Ada 3 suspend
fungsi downloadTask1()
, downloadTask2()
dan downloadTask3()
yang mengunduh data. Untuk mensimulasikannya, saya telah menggunakan delay()
fungsi-fungsi ini. Fungsi-fungsi ini menunggu 5 seconds
, 8 seconds
dan 5 seconds
masing - masing.
Seperti yang telah kita gunakan launch
untuk memulai fungsi-fungsi ini, launch
akan menjalankannya secara berurutan (satu-per-satu) . Ini berarti, downloadTask2()
akan mulai setelah downloadTask1()
selesai dan downloadTask3()
akan mulai hanya setelah downloadTask2()
selesai.
Seperti dalam output screenshot Toast
, total waktu eksekusi untuk menyelesaikan semua 3 download akan menyebabkan 5 detik + 8 detik + 5 detik = 18 detik denganlaunch
- async
Seperti yang kita lihat, ini launch
membuat eksekusi sequentially
untuk semua 3 tugas. Waktu untuk menyelesaikan semua tugas adalah 18 seconds
.
Jika tugas-tugas itu independen dan jika mereka tidak membutuhkan hasil perhitungan tugas lain, kita dapat membuatnya berjalan concurrently
. Mereka akan mulai pada saat yang sama dan berjalan bersamaan di latar belakang. Ini bisa dilakukan dengan async
.
async
mengembalikan sebuah instance dari Deffered<T>
tipe, di mana T
adalah tipe data yang mengembalikan fungsi menangguhkan kami. Sebagai contoh,
downloadTask1()
akan kembali Deferred<String>
karena String adalah jenis kembali fungsidownloadTask2()
akan kembali Deferred<Int>
karena Int adalah jenis pengembalian fungsidownloadTask3()
akan kembali Deferred<Float>
karena Float adalah tipe pengembalian fungsiKita bisa menggunakan objek kembali async
dari tipe Deferred<T>
untuk mendapatkan nilai yang dikembalikan dalam T
tipe. Itu bisa dilakukan dengan await()
panggilan. Periksa kode di bawah ini misalnya
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
}
Dengan cara ini, kami telah meluncurkan ketiga tugas secara bersamaan. Jadi, total waktu eksekusi saya untuk menyelesaikan hanya akan menjadi 8 seconds
waktu karena downloadTask2()
itu adalah yang terbesar dari semua 3 tugas. Anda dapat melihat ini di screenshot berikut diToast message
launch
ini adalah untuk async
launch
dan async
akan memulai coroutine baru. Anda membandingkan coroutine tunggal tanpa anak dengan coroutine tunggal dengan 3 anak. Anda dapat mengganti setiap async
doa dengan launch
dan sama sekali tidak ada yang berubah sehubungan dengan konkurensi.
kedua pembangun coroutine yaitu launch dan async pada dasarnya adalah lambdas dengan penerima tipe CoroutineScope yang berarti blok bagian dalamnya dikompilasi sebagai fungsi menangguhkan, oleh karena itu mereka berdua berjalan dalam mode asinkron dan mereka berdua akan menjalankan blok mereka secara berurutan.
Perbedaan antara peluncuran dan async adalah mereka memungkinkan dua kemungkinan yang berbeda. Pembuat peluncuran mengembalikan suatu Pekerjaan namun fungsi async akan mengembalikan objek yang Ditangguhkan. Anda dapat menggunakan launch untuk mengeksekusi blok yang tidak Anda harapkan nilai yang dikembalikan darinya yaitu menulis ke database atau menyimpan file atau memproses sesuatu yang pada dasarnya hanya dipanggil untuk efek sampingnya. Di sisi lain, async yang mengembalikan Deferred seperti yang saya nyatakan sebelumnya mengembalikan nilai yang berguna dari eksekusi bloknya, sebuah objek yang membungkus data Anda, sehingga Anda dapat menggunakannya terutama untuk hasilnya tetapi juga untuk efek sampingnya. NB: Anda dapat menghapus yang ditangguhkan dan mendapatkan nilainya menggunakan fungsi menunggu, yang akan memblokir eksekusi laporan Anda sampai nilai dikembalikan atau pengecualian dilemparkan!
pembangun coroutine (launch dan async) dapat dibatalkan.
apa lagi ?: ya dengan peluncuran jika pengecualian dilemparkan di dalam bloknya, coroutine secara otomatis dibatalkan dan pengecualian dikirimkan. Di sisi lain, jika itu terjadi dengan async pengecualian tidak diperbanyak lebih lanjut dan harus ditangkap / ditangani dalam objek yang ditangguhkan yang dikembalikan.
lebih lanjut tentang coroutines https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html https://www.codementor.io/blog/kotlin-coroutines-6n53p8cbn1
Peluncuran mengembalikan pekerjaan
async mengembalikan hasil (pekerjaan yang ditangguhkan)
peluncuran dengan bergabung digunakan untuk menunggu sampai pekerjaan selesai. Itu hanya menunda panggilan bergabung coroutine (), meninggalkan utas saat ini bebas untuk melakukan pekerjaan lain (seperti menjalankan coroutine lain) sementara itu.
async digunakan untuk menghitung beberapa hasil. Itu menciptakan coroutine dan mengembalikan hasil masa depannya sebagai implementasi dari Ditangguhkan. Coroutine yang berjalan dibatalkan ketika hasil yang ditangguhkan dibatalkan.
Pertimbangkan metode async yang mengembalikan nilai string. Jika metode async digunakan tanpa menunggu itu akan mengembalikan string yang ditangguhkan tetapi jika menunggu digunakan Anda akan mendapatkan string sebagai hasilnya
Perbedaan utama antara async dan peluncuran. Deferred mengembalikan nilai tipe T tertentu setelah Coroutine Anda selesai dieksekusi, sedangkan Job tidak.
Async vs Launch Async vs Launch Diff Image
luncurkan / async tidak ada hasil
async untuk hasil