Suspend function bir iş parçacığını bloke etmeden yürütmesini duraklatabilen ve daha sonra aynı koroutinde devam edebilen suspend değiştiricisine sahip bir işlevdir. JetBrains Kotlin Docs, 2025'e göre, suspend işlevleri geri aramalar olmadan eşzamansızlık sağlayan koroutinlerin temel yapı taşıdır. Her suspend işlevi, askıya alma noktalarının verimli yönetimine izin veren Continuation tabanlı bir durum makinesine derlenir.
Önemli noktalar
Suspend function, iş parçacığını bloke etmeden bir veya daha fazla noktada yürütmeyi duraklatabilen suspend anahtar sözcüğüyle bildirilmiş bir işlevdir. Başka bir suspend işlevi içindeki her suspend işlevi çağrısı, potansiyel bir askıya alma noktasıdır.
suspend fun fetchUserData(): User {
val response = httpClient.get("/user")
return parser.parse(response)
}
Kotlin derleyicisi böyle bir işlevi durum makinesine dönüştürür. Her askıya alma noktası (başka bir suspend işlevine çağrı) bir durum (label) haline gelir. Geçerli iş parçacığı durumlar arasında serbest bırakılır ve beklenen işlem tamamlandıktan sonra yürütme bir sonraki durumdan devam eder.
Suspend işlevleri, deneysel bir özellik olarak Kotlin 1.3'te (2018) koroutinlerle birlikte ortaya çıktı ve Kotlin 1.5'te (2021) kararlı hale geldi. Bundan önce, Kotlin/Java'da eşzamansızlık geri aramalar, RxJava ve CompletableFuture aracılığıyla sağlanıyordu. Suspend işlevleri, doğrusal sözdizimi ve otomatik iş parçacığı yönetimi ile bir alternatif sundu.
Suspend işlevlerinin iç işleyişini anlamak, koroutinlerle doğru çalışmanın anahtarıdır. Normal işlevlerin aksine, her suspend işlevi Continuation arabirimine sahip bir sınıfa derlenir.
Kotlin derleyicisi, her suspend işlevinin parametre listesinin sonuna Continuation türünde bir parametre ekler. Continuation şunları içerir:
Diyelim ki diğer suspend işlevlerine iki çağrı yapan bir suspend işlevimiz var:
suspend fun process() {
val a = stepOne()
val b = stepTwo(a)
println(b)
}
Derleyici bunu etiketli bir durum makinesine dönüştürür:
// Simplified generated code representation
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
}
}
}
Önemli gözlem: işlev COROUTINE_SUSPENDED döndürürse, geçerli iş parçacığı serbest bırakılır. Eşzamansız işlem tamamlandığında, Continuation.resumeWith çağrılır ve durum makinesi bir sonraki etiketten devam eder.
Bir suspend işlevi bildirmek, fun'dan önceki suspend anahtar sözcüğü dışında normal bir işlevden farklı değildir. Tek bir kısıtlama vardır: bir suspend işlevi yalnızca bir koroutinden veya başka bir suspend işlevinden çağrılabilir.
suspend fun delayAndReturn(ms: Long): String {
delay(ms)
return "Done after ${ms}ms"
}
Bu örnekte, delay de bir suspend işlevidir ve iş parçacığını bloke etmeden koroutini belirtilen milisaniye kadar duraklatır. Gecikmeden sonra yürütme devam eder.
fun main() = runBlocking {
val result = delayAndReturn(1000)
println(result)
}
runBlocking, normal dünya ile koroutinler arasında bir köprü oluşturur. Lambda içinde herhangi bir suspend işlevi çağrılabilir.
Kotlin, işlevsel türlerin suspend sürümlerini destekler — suspend () -> T ve suspend (A) -> B. Bu, eşzamansız lambdaların yüksek dereceli işlevlere iletilmesine olanak tanır:
suspend fun withRetry (
retries: Int = 3,
block: suspend () -> T
): T {
repeat(retries - 1) {
try { return block() }
catch (_: Exception) { delay(100) }
}
return block()
}
withRetry işlevi bir suspend lambda alır ve hata durumunda yürütmesini yeniden dener. Bu, yeniden denemeli ağ istekleri için tipik bir kalıptır.
Suspend ve normal işlevler arasındaki farklar, yalnızca bir değiştirici eklemenin ötesine geçer. Temel farklılıklara bakalım.
| Özellik | Normal işlev | Suspend işlev |
|---|---|---|
| Yürütme iş parçacığı | Tamamlanana kadar iş parçacığını bloke eder | İş parçacığını serbest bırakıp sonra devam edebilir |
| Derleyici parametreleri | Yalnızca belirtilen parametreler | Sonda örtük Continuation |
| Normal işlevden çağrı | Evet | Hayır |
| Yığın | Fiziksel iş parçacığı yığını | Yığında durum makinesi + noktalar arasında fiziksel yığın |
| Dönüş değeri | Doğrudan değer | Değer veya COROUTINE_SUSPENDED |
| Performans | Minimum ek yük | ~durum makinesi başına birkaç nanosaniye (Kotlin 1.9+) |
Normal bir işlevde Continuation yoktur — durumu kaydedecek yeri ve yürütmeyi devam ettirecek bir şeyi yoktur. Normal bir işlevden bir suspend işlevi çağırmanız gerekiyorsa, runBlocking (testler için) veya CoroutineScope.launch (yaşam döngüsü bilinciyle üretim için) kullanın.
Kotlin ile Android uygulamalarında suspend işlevlerini kullanmanın üç gerçek senaryosuna bakalım.
Room, suspend işlevlerini doğrudan destekler — sorgu otomatik olarak bir arka plan iş parçacığında yürütülür:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: Int): User?
@Insert
suspend fun insertUser(user: User)
}
Room, sorguyu yürütmek için dahili olarak Dispatchers.IO kullanır ve sonuç, suspend işlevinin çağrıldığı dağıtıcıda döndürü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 bir koroutin oluşturur ve içinde getProfile suspend işlevi çağrılır. Sonuç alındıktan sonra kullanıcı arayüzü ana iş parçacığında güncellenir.
suspend fun placeOrder(cart: Cart): OrderResult {
val validated = validateCart(cart)
val payment = processPayment(validated)
val receipt = sendReceipt(payment)
return receipt
}
Üç suspend işlevi sırayla yürütülür. Her adımda, koroutin iş parçacığını bloke etmeden duraklayabilir. Herhangi bir adım bir istisna atarsa, kalan adımlar yürütülmez ve bu da hatalı sipariş durumlarına karşı korur.
Deneyimli Kotlin geliştiricileri bile suspend işlevleri tasarlarken hatalar yapar. En yaygın olanlarına bakalım.
Bir suspend işlevi, kodu otomatik olarak eşzamansız yapmaz. Thread.sleep(), InputStream.read() ve diğer bloke edici çağrılar yine de iş parçacığını bloke eder. Bloke edici işlemleri sarmak için withContext(Dispatchers.IO) kullanın.
Bir işlev başka suspend işlevlerini çağırmıyorsa ve eşzamansız işlemler gerçekleştirmiyorsa — suspend değiştiricisi gereksizdir. Durum makinesine ek yük ekler ve çağrı bağlamını kısıtlar. Bir işlevi yalnızca gerçekten durakladığında suspend yapın.
Bir koroutin iptal edildiğinde, suspend işlevleri CancellationException fırlatır. Bunu düşünmeden yakalamayın — çağıran kodu iptali doğru şekilde tamamlama yeteneğinden mahrum bırakırsınız. Sonlandırma işlemi yapmanız gerekiyorsa, bir finally bloğu ve NonCancellable kullanın.
suspend fun safeOperation() {
try {
doWork()
} finally {
withContext(NonCancellable) {
cleanup()
}
}
}
finally bloğu her zaman yürütülür, iptalde dahil, ve NonCancellable temizliğin kesintiye uğramamasını sağlar.
Bir koroutin oluşturmadan doğrudan bir geri aramadan suspend işlevi çağıramazsınız. Geri arama stilini koroutinlere uyarlamak için suspendCoroutine veya suspendCancellableCoroutine kullanın.
Sıkça sorulan sorular
Evet, teknik olarak bir suspend işlevi diğer suspend işlevlerini çağırmayabilir. Derleyici, tek bir durumla (label 0) bir durum makinesi oluşturacaktır. Ancak, böyle bir işlevin pratik bir faydası yoktur — normal bir işlev gibi çalışır ancak ek yük ile. Gereksiz yere suspend kullanmayın.
Kotlin, kotlinx-coroutines-debug sağlar — DebugProbes ve koroutin izleme araçları içeren bir kitaplık. Arctic Fox'tan itibaren Android Studio'da, Hata Ayıklayıcı'da etkin koroutinleri, durumlarını ve askıya alma noktalarını gösteren yerleşik bir Coroutines sekmesi bulunur.
Her askıya alma noktası durum makinesinde yeni bir durum oluşturur. Çoğu uygulama için bir noktanın ek yükü birkaç nanosaniyedir (Kotlin 1.9+). Yalnızca bir döngüde on binlerce nokta olduğunda işlemleri birleştirmeyi veya sequence/flow kullanmayı düşünmelisiniz.
Kotlin'de, suspend bir işlev türü değiştiricisidir, bir dönüş değeri işaretçisi değil (C#'taki async gibi). Herhangi bir suspend işlevi herhangi bir parametreye ve dönüş türüne sahip olabilir ve çağrısı sözdizimsel olarak normal bir işlev çağrısından farklı değildir — çağrı noktasında await operatörü yoktur.
Uyarlama için suspendCancellableCoroutine kullanın. İçinde, continuation.resume() çağıran bir geri arama kaydedersiniz ve geri arama abonelik iptalini destekliyorsa bir iptal belirteci döndürürsünüz. Bu, eski Android API'lerini sarmak için standart kalıptır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun