async — Kotlin-də Coroutine Builder, koorutin işə salan və asinxron əməliyyatın nəticəsini əldə etmək üçün Deferred<T> obyekti qaytaran vasitədir. async bir neçə tapşırığı paralel yerinə yetirməyə və onların nəticələrini await() vasitəsilə toplamağa imkan verir. JetBrains, 2024 təlimatına görə, async koorutinlərdə paralel hesablamaların təşkili üçün üstünlük verilən üsuldur.
Əsas məqamlar
async — nəticə qaytaran koorutin yaradan CoroutineScope genişləndirmə funksiyasıdır. launch-dan fərqli olaraq, async Deferred<T> — gələcək dəyəri təmsil edən obyekt qaytarır. async vasitəsilə işə salınan koorutin digər koorutinlərlə rəqabətli şəkildə icra olunur, bu da hesablamaları paralelləşdirməyə imkan verir.
async asinxron əməliyyatın nəticəsi sonrakı emal üçün lazım olduqda istifadə olunur: birdən çox mənbədən məlumat yükləmə, kolleksiyaların pəkət emalı, müxtəlif API-lərə paralel sorğular. Deferred dərhal yaradılır və nəticə koorutin başa çatdıqdan sonra əlçatan olur.
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 bənzəyir: eyni CoroutineContext, CoroutineStart parametrləri və suspend-bloku. Fərq qaytarılan tipdədir — Job əvəzinə Deferred<T>, burada T blokun son ifadəsi ilə qaytarılan nəticənin tipidir.
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
Deferred<T> — Job-dan miras alan və await(), getCompleted(), getCompletionExceptionOrNull() metodlarını əlavə edən interfeysdir. await() suspend-funksiyadır və yalnız koorutin daxilində və ya digər suspend-funksiyada çağırıla bilər. getCompleted() — bloklamayan metoddur, koorutin hələ başa çatmayıbsa istisna atır.
async-in əsas üstünlüyü tapşırıqları paralel işə salmaq imkanıdır. Ardıcıl gözləmə əvəzinə (ümumi vaxt = vaxtların cəmi), async koorutinləri eyni anda işə salır, ümumi vaxtı ən uzun əməliyyatın vaxtına qədər azaldır.
Tipik ssenari — istifadəçi profili, onun parametrləri və sifariş tarixçəsinin üç paralel async sorğusu ilə yüklənməsi. Hər üçü başa çatdıqdan sonra nəticələr vahid məlumat modelində birləşdirilir.
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 funksiyası alt koorutinləri işə salır və nəticəni qaytarmazdan əvvəl onların başa çatmasını gözləyir. Bütün blok paralel icra olunur, ardıcıl deyil.
Deferred nəticə ilə işləmək üçün bir neçə metodu dəstəkləyir. await() ilə yanaşı, statusu yoxlamaq, hazır dəyəri almaq və Kotlin Coroutines köməkçi funksiyaları vasitəsilə çoxsaylı Deferred-ləri toplamaq üçün metodlar mövcuddur.
| Metod | Təsvir | Suspend? |
|---|---|---|
| await() | Nəticəni əldə edənə qədər koorutini dayandırır | Bəli |
| getCompleted() | Koorutin başa çatıbsa nəticəni qaytarır (əks halda Exception) | Xeyr |
| getCompletionExceptionOrNull() | Səhv olduqda istisnanı və ya null qaytarır | Xeyr |
| isCompleted | Koorutinin başa çatıb-çatmadığını yoxlayır | Xeyr |
Deferred siyahısını toplamaq üçün awaitAll() — kolleksiyadakı bütün Deferred-lər başa çatana qədər icranı dayandıran funksiya istifadə olunur. Əgər ən azı biri səhvlə başa çatıbsa, awaitAll() istisna atır.
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
return coroutineScope {
val deferreds = requests.map { async { it() } }
deferreds.awaitAll()
}
}
async və launch arasında seçim koorutinin icra nəticəsinin lazım olub-olmamasından asılıdır. launch Job qaytarır və fire-and-forget əməliyyatları üçün uyğundur, async Deferred qaytarır və məlumat qaytaran tapşırıqlar üçün istifadə olunur. Sintaksis və parametrlər baxımından qurucular eynidir.
Əhəmiyyətli qayda: fire-and-forget üçün async istifadə etməyin. Koorutinin nəticəsi lazım deyilsə, launch istifadə edin. async Deferred yaratmaq üçün əlavə yük yaradır ki, bu da belə ssenaridə əsaslandırılmır.
Android-də async ViewModel və UseCases daxilində paralel əməliyyatlar üçün istifadə olunur. Tipik ssenarilər: profil və xəbər lentinin eyni vaxtda yüklənməsi, bir neçə hava xidmətindən hava məlumatının alınması, serverlə pəkət məlumat sinxronizasiyası.
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 }
}
}
}
Xətaların izolyasiyası üçün async qrupunu coroutineScope və ya supervisorScope ilə bükmək tövsiyə olunur. supervisorScope bir async-də səhv olsa belə, qalan async koorutinlərinin icrasını davam etdirməyə imkan verir — bu kritik olmayan əməliyyatlar üçün faydalıdır.
Tez-tez verilən suallar
Olar, amma mənasızdır. await() olmadan async koorutini işə salır, amma nəticə itir. Nəticə lazım deyilsə, launch istifadə edin — o Deferred yaratmır və yaddaş və performans baxımından daha səmərəlidir.
async daxilindəki istisna Deferred-də saxlanılır. await() çağırışı bu istisnanı ötürür. Ötürmədən yoxlamaq üçün getCompletionExceptionOrNull() istifadə edin. coroutineScope istifadə edərkən xəta bütün alt koorutinləri ləğv edir.
awaitAll() — Iterable<Deferred<T>> üçün genişləndirmə funksiyası, bütün Deferred-lər başa çatana qədər koorutini dayandırır. Nəticələrin siyahısını qaytarır. Ən azı bir Deferred səhvlə başa çatarsa, istisna atır və qalanlarını ləğv edir.
Bəli. async — CoroutineScope-un genişləndirmə funksiyasıdır, scope-a bağlıdır. GlobalScope.async həyat dövrünə bağlı olmayan koorutin yaradır — sonsuz icra oluna bilər. Android-də sızma riski səbəbindən GlobalScope tövsiyə edilmir.
Say dispatcher tərəfindən müəyyən edilir: Dispatchers.IO 64 eyni vaxtda işləyən thread-ə qədər, Dispatchers.Default — CPU nüvələrinin sayına görə dəstəkləyir. Kütləvi əməliyyatlar üçün Semaphore və ya mapNotNull ilə awaitAll vasitəsilə məhdud paralellikdən istifadə edin.
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