async — Kotlin'de bir Coroutine Builder'dır, bir coroutine başlatır ve asenkron bir işlemin sonucunu almak için Deferred<T> nesnesi döndürür. async, birden çok görevi paralel olarak yürütmeye ve sonuçlarını await() aracılığıyla birleştirmeye olanak tanır. JetBrains rehberine göre, 2024, async, coroutine'lerde paralel hesaplamaları düzenlemenin tercih edilen yoludur.
Ana Noktalar
async — bir sonuç döndüren bir coroutine oluşturan CoroutineScope uzantı fonksiyonudur. launch'tan farklı olarak, async Deferred<T> döndürür — gelecekteki bir değeri temsil eden bir nesne. async ile başlatılan bir coroutine, diğer coroutine'lerle eşzamanlı olarak çalışarak hesaplamaların paralelleştirilmesine olanak tanır.
async, asenkron bir işlemin sonucunun daha sonraki işlemler için gerekli olduğu durumlarda kullanılır: birden çok kaynaktan veri yükleme, koleksiyonların toplu işlenmesi, çeşitli API'lere paralel istekler. Deferred hemen oluşturulur ve sonuç, coroutine tamamlandıktan sonra kullanılabilir hale gelir.
import kotlinx.coroutines.*
suspend fun String.delayedValue(): String {
delay(1000L)
return this
}
fun main() = runBlocking {
val deferred: Deferred<String> = async { "Hello".delayedValue() }
println(deferred.await())
}
async'in imzası launch'a benzer: aynı CoroutineContext, CoroutineStart parametreleri ve bir suspend bloğu. Fark, dönüş türündedir — Job yerine Deferred<T>, burada T bloğun son ifadesi tarafından döndürülen sonuç türüdür.
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
Deferred<T> — Job'u miras alan ve await(), getCompleted(), getCompletionExceptionOrNull() metodlarını ekleyen bir arayüzdür. await() bir suspend fonksiyonudur ve yalnızca bir coroutine veya başka bir suspend fonksiyonu içinde çağrılabilir. getCompleted(), coroutine henüz tamamlanmadıysa bir istisna fırlatan engelleyici olmayan bir metottur.
async'in ana avantajı, görevleri paralel olarak yürütme yeteneğidir. Her işlemi sırayla beklemek yerine (toplam süre = sürelerin toplamı), async coroutine'leri aynı anda başlatarak toplam süreyi en uzun işlem süresine indirir.
Tipik bir senaryo — üç paralel async isteğiyle kullanıcı profili, ayarları ve sipariş geçmişini yüklemek. Üçü de tamamlandıktan sonra sonuçlar tek bir veri modelinde birleştirilir.
suspend fun loadUserDashboard(userId: String): Dashboard = coroutineScope {
val profile = async { api.getProfile(userId) }
val settings = async { api.getSettings(userId) }
val orders = async { api.getRecentOrders(userId) }
Dashboard(
profile = profile.await(),
settings = settings.await(),
orders = orders.await()
)
}
coroutineScope fonksiyonu alt coroutine'leri başlatır ve sonucu döndürmeden önce tamamlanmalarını bekler. Bloğun tamamı sıralı değil, paralel olarak yürütülür.
Deferred, sonuçla çalışmak için birden çok metodu destekler. await()'e ek olarak, durumu kontrol etme, tamamlanmış değeri alma ve Kotlin Coroutines yardımcı fonksiyonları aracılığıyla birden çok Deferred'i birleştirme metodları vardır.
| Metot | Açıklama | Suspend? |
|---|---|---|
| await() | Sonuç elde edilene kadar coroutine'i askıya alır | Evet |
| getCompleted() | Coroutine tamamlandıysa sonucu döndürür (yoksa Exception) | Hayır |
| getCompletionExceptionOrNull() | Hata durumunda istisnayı veya null döndürür | Hayır |
| isCompleted | Coroutine'in tamamlanıp tamamlanmadığını kontrol eder | Hayır |
Bir Deferred listesini birleştirmek için awaitAll() kullanılır — koleksiyondaki tüm Deferred'ler tamamlanana kadar yürütmeyi askıya alan bir fonksiyon. En az biri hatayla tamamlanırsa, awaitAll() istisnayı fırlatır.
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
return coroutineScope {
val deferreds = requests.map { async { it() } }
deferreds.awaitAll()
}
}
async ve launch arasındaki seçim, coroutine sonucunun gerekli olup olmadığına bağlıdır. launch Job döndürür ve fire-and-forget işlemleri için uygundur, async Deferred döndürür ve veri döndüren görevler için kullanılır. Sözdizimi ve parametreler açısından builder'lar aynıdır.
Önemli kural: fire-and-forget için asla async kullanmayın. Coroutine sonucu gerekli değilse, launch kullanın. async, Deferred oluşturma yükü getirir ve bu tür senaryolarda haklı gösterilemez.
Android'de async, ViewModel ve UseCases içindeki paralel işlemler için kullanılır. Tipik senaryolar: profil ve haber akışını aynı anda yükleme, birden çok hava durumu servisinden hava durumu alma, sunucuyla toplu veri senkronizasyonu.
class HomeViewModel : ViewModel() {
fun loadHomeScreen() {
viewModelScope.launch {
val userData = async(Dispatchers.IO) { repository.getUserData() }
val newsFeed = async(Dispatchers.IO) { repository.getNewsFeed() }
val notifications = async(Dispatchers.IO) { repository.getNotifications() }
val state = HomeState(
user = userData.await(),
news = newsFeed.await(),
unread = notifications.await()
)
_uiState.update { state }
}
}
}
Hata yalıtımı için bir async grubunun coroutineScope veya supervisorScope ile sarılması önerilir. supervisorScope, biri başarısız olsa bile diğer async coroutine'lerin devam etmesine izin verir — kritik olmayan işlemler için kullanışlıdır.
Sıkça Sorulan Sorular
Kullanılabilir, ancak anlamsızdır. await() olmadan async bir coroutine başlatır ancak sonucu kaybolur. Sonuç gerekli değilse, launch kullanın — Deferred oluşturmaz ve bellek ve performans açısından daha verimlidir.
async içindeki bir istisna Deferred'de saklanır. await() çağrısı bu istisnayı fırlatır. Fırlatmadan kontrol etmek için getCompletionExceptionOrNull() kullanın. coroutineScope kullanıldığında, bir hata tüm alt coroutine'leri iptal eder.
awaitAll() — Iterable<Deferred<T>> için bir uzantı fonksiyonudur, tüm Deferred'ler tamamlanana kadar coroutine'i askıya alır. Sonuçların bir listesini döndürür. En az bir Deferred başarısız olursa, istisnayı fırlatır ve kalanları iptal eder.
Evet. async, kapsama bağlı bir CoroutineScope uzantı fonksiyonudur. GlobalScope.async yaşam döngüsüne bağlı olmayan bir coroutine oluşturur — süresiz olarak çalışabilir. GlobalScope, sızıntı riski nedeniyle Android'de önerilmez.
Sayı, dağıtıcı tarafından belirlenir: Dispatchers.IO en fazla 64 eşzamanlı iş parçacığını destekler, Dispatchers.Default — CPU çekirdeği sayısına kadar. Toplu işlemler için Semaphore veya awaitAll ile mapNotNull aracılığıyla sınırlı paralellik kullanın.
Ö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