Suspend function — bu, suspend modifikatoru olan, axını bloklamadan icrasını dayandıra və daha sonra eyni korutində davam etdirə bilən funksiyadır. JetBrains Kotlin Docs, 2025-ə görə, suspend funksiyaları korutinlərin əsas tikinti blokudur, callback-lər olmadan asinxronluğu təmin edir. Hər bir suspend funksiyası Continuation əsasında state-maşınına kompilyasiya olunur ki, bu da dayandırma nöqtələrini səmərəli idarə etməyə imkan verir.
Əsas məqamlar
Suspend function — suspend açar sözü ilə elan edilmiş, axını bloklamadan bir və ya bir neçə nöqtədə icranı dayandıra bilən funksiyadır. Digər suspend funksiyasının daxilində hər bir suspend funksiyası çağırışı potensial dayandırma nöqtəsidir.
suspend fun fetchUserData(): User {
val response = httpClient.get("/user")
return parser.parse(response)
}
Kotlin kompilyatoru belə bir funksiyanı state-maşınına çevirir. Hər bir dayandırma nöqtəsi (digər suspend funksiyasının çağırışı) state (label) olur. Cari axın state-lər arasında sərbəst buraxılır və gözlənilən əməliyyat bitdikdən sonra icra növbəti state-dən davam edir.
Suspend funksiyaları Kotlin 1.3-də (2018-ci il) korutinlərlə birlikdə eksperimental xüsusiyyət olaraq ortaya çıxdı və Kotlin 1.5-də (2021-ci il) stabil oldu. Bundan əvvəl Kotlin/Java-da asinxronluq callback-lər, RxJava və CompletableFuture vasitəsilə təmin edilirdi. Suspend funksiyaları xətti sintaksis və avtomatik axın idarəetməsi ilə alternativ təklif etdi.
Suspend funksiyalarının daxili quruluşunu başa düşmək korutinlərlə düzgün işin açarıdır. Adi funksiyalardan fərqli olaraq, hər bir suspend funksiyası Continuation interfeysi olan sinfə kompilyasiya olunur.
Kotlin kompilyatoru suspend funksiyasının hər bir parametrinin sonuna Continuation tipli parametr əlavə edir. Continuation aşağıdakıları ehtiva edir:
Tutaq ki, digər suspend funksiyalarına iki çağırışı olan suspend funksiyamız var:
suspend fun process() {
val a = stepOne()
val b = stepTwo(a)
println(b)
}
Kompilyator onu etiketlərlə state-maşınına çevirir:
// Sadələşdirilmiş yaradılmış kod təsviri
fun process(cont: Continuation<Unit>): Any? {
val cont = cont as ProcessContinuation
when (cont.label) {
0 -> {
cont.label = 1
if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
}
1 -> {
cont.label = 2
val a = cont.result as TypeA
if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
}
2 -> {
println(cont.result)
Unit
}
}
}
Əsas müşahidə: funksiya COROUTINE_SUSPENDED qaytararsa, cari axın sərbəst buraxılır. Asinxron əməliyyat bitdikdə Continuation.resumeWith çağırılır və state-maşını növbəti label-dən davam edir.
Suspend funksiyasının elanı adi funksiyadan fərqlənmir, yalnız fun-dən əvvəl suspend açar sözü əlavə olunur. Yalnız bir məhdudiyyət var: suspend funksiyasını yalnız korutindən və ya digər suspend funksiyasından çağırmaq olar.
suspend fun delayAndReturn(ms: Long): String {
delay(ms)
return "Done after ${ms}ms"
}
Bu nümunədə delay də suspend funksiyasıdır, korutinanı axını bloklamadan müəyyən millisaniyə dayandırır. Gecikmədən sonra icra bərpa olunur.
fun main() = runBlocking {
val result = delayAndReturn(1000)
println(result)
}
runBlocking adi dünya ilə korutinlər arasında körpü yaradır. Lambda daxilində istənilən suspend funksiyasını çağırmaq mümkündür.
Kotlin funksional tiplərin suspend versiyalarını dəstəkləyir — suspend () -> T və suspend (A) -> B. Bu, asinxron lambdaları yüksək səviyyəli funksiyalara ötürməyə imkan verir:
suspend fun withRetry (
retries: Int = 3,
block: suspend () -> T
): T {
repeat(retries - 1) {
try { return block() }
catch (_: Exception) { delay(100) }
}
return block()
}
withRetry funksiyası suspend lambda qəbul edir və səhvlər zamanı onu təkrar icra edir. Bu, təkrar cəhdlərlə şəbəkə sorğuları üçün tipik nümunədir.
Suspend və adi funksiyalar arasındakı fərqlər sadəcə modifikator əlavə etməkdən kənara çıxır. Əsas fərqləri nəzərdən keçirək.
| Xüsusiyyət | Adi funksiya | Suspend funksiyası |
|---|---|---|
| İcra axını | Axını bitənə qədər bloklayır | Axını sərbəst buraxıb sonra davam edə bilər |
| Kompilyator parametrləri | Yalnız göstərilən parametrlər | Sonda gizli Continuation |
| Adi funksiyadan çağırış | Bəli | Xeyr |
| Stack | Fiziki axın stack-i | Heap-da state-maşını + nöqtələr arasında fiziki stack |
| Qaytarma | Birbaşa dəyər | Dəyər və ya COROUTINE_SUSPENDED |
| Performans | Minimal əlavə yük | ~state-maşını üçün bir neçə nanosaniyə (Kotlin 1.9+) |
Adi funksiyanın Continuation-ı yoxdur — vəziyyəti saxlamağa və icranı bərpa etməyə yeri yoxdur. Adi funksiyadan suspend funksiyasını çağırmaq lazımdırsa, runBlocking (testlər üçün) və ya CoroutineScope.launch (istehsalat üçün lifecycle nəzərə alınmaqla) istifadə edin.
Kotlin dilində Android tətbiqlərində suspend funksiyalarından istifadənin üç real ssenarisini nəzərdən keçirək.
Room suspend funksiyalarını birbaşa dəstəkləyir — sorğu avtomatik olaraq fon axınında icra olunur:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: Int): User?
@Insert
suspend fun insertUser(user: User)
}
Room daxili olaraq sorğunun icrası üçün Dispatchers.IO istifadə edir və nəticə suspend funksiyasının çağırıldığı dispetçerə qaytarılır.
class ProfileViewModel : ViewModel() {
private val repo = ProfileRepository()
fun loadProfile(id: String) {
viewModelScope.launch {
val profile = repo.getProfile(id)
_profile.value = profile
}
}
}
ViewModelScope.launch korutin yaradır, onun daxilində getProfile suspend funksiyası çağırılır. Nəticə alındıqdan sonra UI əsas axında yenilənir.
suspend fun placeOrder(cart: Cart): OrderResult {
val validated = validateCart(cart)
val payment = processPayment(validated)
val receipt = sendReceipt(payment)
return receipt
}
Üç suspend funksiyası ardıcıl olaraq icra olunur. Hər addımda korutin axını bloklamadan dayana bilər. Əgər hansısa addım istisna atarsa — qalanları icra olunmur, bu da sifarişin yanlış vəziyyətlərindən qoruyur.
Hətta təcrübəli Kotlin proqramçıları suspend funksiyalarının layihələndirilməsində səhvlərə yol verirlər. Ən çox yayılanları nəzərdən keçirək.
Suspend funksiyası kodu avtomatik olaraq asinxron etmir. Thread.sleep(), InputStream.read() və digər bloklayan çağırışlar yenə də axını bloklayacaq. Bloklayan əməliyyatları bükmək üçün withContext(Dispatchers.IO) istifadə edin.
Əgər funksiya digər suspend funksiyalarını çağırmırsa və asinxron əməliyyatlar yerinə yetirmirsə — suspend modifikatoru artıqdır. State-maşınına əlavə yük gətirir və çağırış kontekstini məhdudlaşdırır. Funksiyanı yalnız o zaman suspend edin ki, həqiqətən dayandırılır.
Korutin ləğv edildikdə suspend funksiyaları CancellationException atır. Onu düşünmədən tutmayın — çağıran kodu ləğvi düzgün başa çatdırmaq imkanından məhrum edirsiniz. Finalizasiya əməliyyatı yerinə yetirmək lazımdırsa, finally bloku və NonCancellable istifadə edin.
suspend fun safeOperation() {
try {
doWork()
} finally {
withContext(NonCancellable) {
cleanup()
}
}
}
finally bloku həmişə icra olunur, ləğv də daxil olmaqla, NonCancellable isə cleanup-ın kəsilməyəcəyini təmin edir.
Korutin yaratmadan callback-dən birbaşa suspend funksiyasını çağırmaq mümkün deyil. Callback üslubunu korutinlərə uyğunlaşdırmaq üçün suspendCoroutine və ya suspendCancellableCoroutine istifadə edin.
Tez-tez verilən suallar
Bəli, texniki olaraq suspend funksiyası digər suspend funksiyalarını çağırmaya bilər. Kompilyator bir state-li (label 0) state-maşını yaradacaq. Lakin belə funksiyanın praktiki faydası yoxdur — adi funksiya kimi icra olunur, ancaq əlavə yüklə. Ehtiyac olmadan suspend istifadə etməyin.
Kotlin kotlinx-coroutines-debug kitabxanasını təmin edir — DebugProbes və korutin izləmə alətləri ilə. Arctic Fox versiyasından başlayaraq Android Studio-da Debugger-də Coroutines əlavə nişanı var, aktiv korutinləri, onların vəziyyətini və dayandırma nöqtələrini göstərir.
Hər dayandırma nöqtəsi state-maşınında yeni state yaradır. Əksər tətbiqlər üçün bir nöqtənin əlavə yükü nanosaniyələr təşkil edir (Kotlin 1.9+). Yalnız dövrədə on minlərlə nöqtə olduqda əməliyyatları birləşdirmək və ya sequence/flow istifadə etmək məsləhətdir.
Kotlin-də suspend funksiya tipinin modifikatorudur, qaytarılan dəyərin işarəsi deyil (C#-də async kimi). İstənilən suspend funksiyası istənilən parametr və qaytarılan tipə malik ola bilər və onun çağırışı sintaktik olaraq adi funksiya çağırışından fərqlənmir — çağırış yerində await operatoru yoxdur.
Uyğunlaşdırma üçün suspendCancellableCoroutine istifadə edin. Daxildə continuation.resume() çağıran callback qeydiyyatını ötürürsünüz və callback abunəlikdən çıxmağı dəstəkləyirsə, ləğv tokeni qaytarırsınız. Bu, köhnə Android API-lərini bükmək üçün standart nümunədir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun