Saya membaca Kotlin Coroutine dan tahu bahwa ini didasarkan pada suspend
fungsi. Tapi apa suspend
artinya?
Coroutine atau fungsi ditangguhkan?
Dari https://kotlinlang.org/docs/reference/coroutines.html
Pada dasarnya, coroutine adalah komputasi yang dapat ditangguhkan tanpa memblokir utas
Saya mendengar orang sering mengatakan "fungsi tunda". Tapi menurut saya coroutine-nya yang di-suspend karena menunggu fungsinya selesai? "suspend" biasanya berarti "hentikan operasi", dalam hal ini coroutine dalam keadaan idle.
🤔 Haruskah kita mengatakan coroutine ditangguhkan?
Coroutine mana yang ditangguhkan?
Dari https://kotlinlang.org/docs/reference/coroutines.html
Untuk melanjutkan analoginya, await () bisa menjadi fungsi penangguhan (karenanya juga bisa dipanggil dari dalam blok {} async) yang menangguhkan coroutine sampai beberapa komputasi selesai dan mengembalikan hasilnya:
async { // Here I call it the outer async coroutine
...
// Here I call computation the inner coroutine
val result = computation.await()
...
}
🤔 Dikatakan "yang menangguhkan coroutine sampai beberapa komputasi selesai", tetapi coroutine seperti thread yang ringan. Jadi, jika coroutine di-suspend, bagaimana komputasi bisa dilakukan?
Kami melihat await
dipanggil computation
, jadi mungkin async
itu kembali Deferred
, yang berarti dapat memulai coroutine lain
fun computation(): Deferred<Boolean> {
return async {
true
}
}
🤔 Kutipan mengatakan bahwa menghentikan coroutine . Apakah itu berarti coroutine suspend
luar async
, atau coroutine suspend
dalam computation
?
Apakah suspend
berarti bahwa sementara async
coroutine luar sedang menunggu ( await
) untuk computation
coroutine bagian dalam selesai, itu ( async
coroutine luar ) menganggur (karena itu nama menangguhkan) dan mengembalikan utas ke kumpulan utas, dan ketika computation
coroutine turunan selesai, itu ( async
coroutine luar ) bangun, mengambil utas lain dari kolam dan melanjutkan?
Alasan saya menyebutkan utas ini adalah karena https://kotlinlang.org/docs/tutorials/coroutines-basic-jvm.html
Utas dikembalikan ke kumpulan saat coroutine menunggu, dan saat penantian selesai, coroutine dilanjutkan pada utas gratis di kumpulan
sumber
suspend fun
bisa dijeda tapi bagaimana tepatnya?Untuk memahami apa sebenarnya artinya menangguhkan coroutine, saya sarankan Anda membaca kode ini:
Operator
Unconfined
coroutine menghilangkan keajaiban pengiriman coroutine dan memungkinkan kita untuk fokus langsung pada coroutine kosong.Kode di dalam
launch
blok mulai dijalankan langsung di utas saat ini, sebagai bagian darilaunch
panggilan. Yang terjadi adalah sebagai berikut:val a = a()
b()
, mencapaisuspendCoroutine
.b()
mengeksekusi blok yang diteruskansuspendCoroutine
dan kemudian mengembalikanCOROUTINE_SUSPENDED
nilai khusus . Nilai ini tidak dapat diamati melalui model pemrograman Kotlin, tetapi itulah yang dilakukan metode Java yang dikompilasi.a()
, melihat nilai kembalian ini, juga mengembalikannya.launch
blok melakukan hal yang sama dan kontrol sekarang kembali ke jalur setelahlaunch
doa:10.downTo(0)...
Perhatikan bahwa, pada titik ini, Anda memiliki efek yang sama seperti jika kode di dalam
launch
blok danfun main
kode Anda dijalankan secara bersamaan. Kebetulan semua ini terjadi pada satu utas asli sehinggalaunch
blok "ditangguhkan".Sekarang, di dalam
forEach
kode perulangan, program membacacontinuation
bahwab()
fungsi tersebut menulis danresumes
dengan nilai10
.resume()
diimplementasikan sedemikian rupa sehingga seakan-akansuspendCoroutine
panggilan itu dikembalikan dengan nilai yang Anda berikan. Jadi, Anda tiba-tiba menemukan diri Anda berada di tengah-tengah eksekusib()
. Nilai yang Andaresume()
berikan akan ditetapkani
dan diperiksa0
. Jika bukan nol,while (true)
loop berlanjut ke dalamb()
, lagi-lagi mencapaisuspendCoroutine
, di manaresume()
panggilan Anda kembali, dan sekarang Anda melalui langkah perulangan lainnyaforEach()
. Ini berlangsung sampai akhirnya Anda melanjutkan0
, kemudianprintln
pernyataan berjalan dan program selesai.Analisis di atas akan memberi Anda intuisi penting bahwa "menangguhkan coroutine" berarti mengembalikan kontrol ke
launch
pemanggilan terdalam (atau, lebih umum, pembuat coroutine ). Jika coroutine dihentikan lagi setelah dilanjutkan,resume()
panggilan berakhir dan kontrol kembali ke pemanggilresume()
.Kehadiran petugas operator coroutine membuat alasan ini kurang jelas karena kebanyakan dari mereka segera mengirimkan kode Anda ke utas lain. Dalam hal ini, cerita di atas terjadi di utas lain itu, dan dispatcher coroutine juga mengelola
continuation
objek tersebut sehingga dapat melanjutkannya ketika nilai yang dikembalikan tersedia.sumber
Pertama-tama, sumber terbaik untuk memahami IMO ini adalah ceramah "Menyelam Mendalam ke Coroutines" oleh Roman Elizarov.
Memanggil menangguhkan ing fungsi menangguhkan s coroutine, yang berarti benang saat dapat mulai menjalankan coroutine lain. Jadi, coroutine dikatakan ditangguhkan daripada fungsinya.
Faktanya, situs panggilan untuk fungsi penangguhan disebut "titik penangguhan" karena alasan ini.
Mari kita lihat kode Anda dan uraikan apa yang terjadi:
Bagian luar
async
memulai coroutine. Saat dipanggilcomputation()
, bagian dalamasync
memulai coroutine kedua. Kemudian, panggilan untukawait()
menunda pelaksanaan luarasync
coroutine, sampai pelaksanaan dalamasync
coroutine 's berakhir.Anda bahkan dapat melihatnya dengan satu utas: utas akan mengeksekusi bagian luar
async
awal, kemudian memanggilcomputation()
dan mencapai bagian dalamasync
. Pada titik ini, badan asinkron bagian dalam dilewati, dan utas terus mengeksekusi bagian luarasync
hingga mencapaiawait()
.await()
adalah "titik suspensi", karenaawait
merupakan fungsi penangguhan. Ini berarti bahwa coroutine luar ditangguhkan, dan dengan demikian thread mulai mengeksekusi yang dalam. Setelah selesai, ia kembali untuk mengeksekusi ujung luarasync
.Ya, tepatnya.
Cara ini sebenarnya dicapai adalah dengan mengubah setiap fungsi penangguhan menjadi mesin keadaan, di mana setiap "keadaan" sesuai dengan titik suspensi di dalam fungsi penangguhan ini. Di bawah kap, fungsi tersebut dapat dipanggil beberapa kali, dengan informasi tentang titik penangguhan mana yang harus mulai dijalankan (Anda harus benar-benar menonton video yang saya tautkan untuk info lebih lanjut tentang itu).
sumber
async
fungsi JS yang ditandai dengan cara ini, namun tetap mengembalikan Promise.Saya telah menemukan bahwa cara terbaik untuk memahaminya
suspend
adalah dengan membuat analogi antarathis
kata kunci dancoroutineContext
properti.Fungsi Kotlin dapat dideklarasikan sebagai lokal atau global. Fungsi lokal secara ajaib memiliki akses ke
this
kata kunci sementara global tidak.Fungsi Kotlin dapat dideklarasikan sebagai
suspend
atau memblokir.suspend
fungsi secara ajaib memiliki akses kecoroutineContext
properti sementara fungsi pemblokiran tidak.Masalahnya adalah:
coroutineContext
properti dideklarasikan seperti properti "normal" di Kotlin stdlib tetapi deklarasi ini hanyalah sebuah rintisan untuk keperluan dokumentasi / navigasi. BahkancoroutineContext
yang builtin properti intrinsik yang berarti di bawah tenda compiler sihir menyadari properti ini seperti itu menyadari kata kunci bahasa.Apa yang
this
dilakukan kata kunci untuk fungsi lokal adalah apa yangcoroutineContext
dilakukan properti untuksuspend
fungsi: ia memberikan akses ke konteks eksekusi saat ini.Jadi, Anda perlu
suspend
mendapatkan akses kecoroutineContext
properti - contoh konteks coroutine yang saat ini dijalankansumber
Saya ingin memberi Anda contoh sederhana tentang konsep kelanjutan. Inilah yang dilakukan fungsi penangguhan, dapat membekukan / menangguhkan dan kemudian melanjutkan / melanjutkan. Berhenti memikirkan coroutine dalam kaitannya dengan utas dan Semaphore. Anggap saja dalam istilah kelanjutan dan bahkan kait panggilan balik.
Agar jelas, coroutine dapat dijeda dengan menggunakan suatu
suspend
fungsi. mari selidiki ini:Di android kita bisa melakukan ini sebagai contoh:
Kode di atas mencetak yang berikut ini:
bayangkan itu bekerja seperti ini:
Jadi fungsi yang saat ini Anda luncurkan tidak berhenti, hanya coroutine yang akan ditangguhkan sementara itu berlanjut. Utas tidak dihentikan sementara dengan menjalankan fungsi penangguhan.
Saya pikir situs ini dapat membantu Anda menyelesaikan masalah dan merupakan referensi saya.
Mari lakukan sesuatu yang keren dan bekukan fungsi penangguhan kita di tengah iterasi. Kami akan melanjutkannya nanti
onResume
Simpan variabel yang dipanggil
continuation
dan kita akan memuatnya dengan objek lanjutan coroutines untuk kita:Sekarang, mari kembali ke fungsi yang ditangguhkan dan membuatnya berhenti di tengah iterasi:
Kemudian di tempat lain seperti di onResume (misalnya):
Dan loop akan terus berlanjut. Cukup rapi untuk mengetahui bahwa kita dapat membekukan fungsi penangguhan kapan saja dan melanjutkannya setelah beberapa waktu berlalu. Anda juga dapat melihat saluran
sumber
Karena banyak jawaban bagus sudah ada, saya ingin memposting contoh yang lebih sederhana untuk orang lain.
suspend
fungsirunBlocking { }
memulai Coroutine dengan cara memblokir. Ini mirip dengan cara kami memblokir utas normal denganThread
kelas dan memberi tahu utas yang diblokir setelah kejadian tertentu.runBlocking { }
tidak memblokir arus mengeksekusi benang, sampai coroutine (tubuh antara{}
) akan selesaiOutput ini:
launch { }
memulai coroutine secara bersamaan.worker
thread.worker
benang dan benang luar (dari mana kita disebutlaunch { }
) keduanya berjalan bersamaan. Secara internal, JVM dapat melakukan Preemptive ThreadingSaat kami membutuhkan banyak tugas untuk dijalankan secara paralel, kami dapat menggunakan ini. Ada
scopes
yang menentukan masa pakai coroutine. Jika kita tentukanGlobalScope
, coroutine akan bekerja sampai masa pakai aplikasi berakhir.Keluaran ini:
async
danawait
akan membantu.2
fungsi suspend myMethod () dan myMethod2 ().myMethod2()
harus dieksekusi hanya setelah penyelesaian penuhmyMethod()
ATAUmyMethod2()
tergantung pada hasilmyMethod()
, kita dapat menggunakanasync
danawait
async
memulai coroutine secara paralel mirip denganlaunch
. Namun, ini memberikan cara untuk menunggu satu coroutine sebelum memulai coroutine lain secara paralel.Begitulah
await()
.async
mengembalikan sebuah instance dariDeffered<T>
.T
akan menjadiUnit
default. Ketika kita perlu menunggu untuk setiapasync
's selesai, kita perlu panggilan.await()
padaDeffered<T>
contoh yangasync
. Seperti pada contoh di bawah ini, kami memanggilinnerAsync.await()
yang menyiratkan bahwa eksekusi akan ditangguhkan sampaiinnerAsync
selesai. Kita dapat mengamati hal yang sama pada keluarannya. YanginnerAsync
selesai pertama, yang panggilanmyMethod()
. Dan kemudianasync
innerAsync2
dimulai berikutnya , yang memanggilmyMethod2()
Output ini:
sumber