async — Coroutine Builder у Kotlin-у који покреће корутину и враћа објекат Deferred<T> за добијање резултата асинхроне операције. async омогућава паралелно извршавање више задатака и агрегирање њихових резултата преко await(). Према JetBrains водичу, 2024, async је пожељан начин организације паралелних израчунавања у корутинама.
Главно
async — функција проширења CoroutineScope која ствара корутину са враћањем резултата. За разлику од launch, async враћа Deferred<T> — објекат који представља будућу вриједност. Корутина покренута преко async извршава се конкурентно са другим корутинама, што омогућава паралелизацију израчунавања.
async се користи када је резултат асинхроне операције потребан за даљу обраду: учитавање података из више извора, пакетна обрада колекција, паралелни захтјеви различитим API-јима. Deferred се ствара одмах, а резултат постаје доступан након завршетка корутине.
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 је сличан launch: исти параметри CoroutineContext, CoroutineStart и suspend-блок. Разлика је у типу који се враћа — Deferred<T> умјесто Job, гдје је T тип резултата који враћа посљедњи израз блока.
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
Deferred<T> — интерфејс који насљеђује Job и додаје методе await(), getCompleted(), getCompletionExceptionOrNull(). await() је suspend-функција и може се позвати само унутар корутине или друге suspend-функције. getCompleted() — метод који не блокира, баца изузетак ако корутина још није завршена.
Главна предност async-а је могућност покретања задатака паралелно. Умјесто секвенцијалног чекања на сваку операцију (укупно вријеме = збир времена), async покреће корутине истовремено, смањујући укупно вријеме на вријеме најдуже операције.
Типичан сценарио — учитавање профила корисника, његових поставки и историје наруџбина са три паралелна async захтјева. Након завршетка све три, резултати се обједињују у јединствени модел података.
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 покреће подређене корутине и чека њихов завршетак прије враћања резултата. Цијели блок се извршава паралелно, а не секвенцијално.
Deferred подржава неколико метода за рад са резултатом. Поред await(), доступне су методе за провјеру статуса, добијање готове вриједности и агрегацију више Deferred преко помоћних функција Kotlin Coroutines.
| Метод | Опис | Suspend? |
|---|---|---|
| await() | Зауставља корутину до добијања резултата | Да |
| getCompleted() | Враћа резултат ако је корутина завршена (иначе Exception) | Не |
| getCompletionExceptionOrNull() | Враћа изузетак при грешци или null | Не |
| isCompleted | Провјерава да ли је корутина завршена | Не |
За агрегацију листе Deferred користи се awaitAll() — функција која зауставља извршавање док се не заврше сви Deferred у колекцији. Ако се барем један завршио са грешком, awaitAll() баца изузетак.
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
return coroutineScope {
val deferreds = requests.map { async { it() } }
deferreds.awaitAll()
}
}
Избор између async и launch зависи од тога да ли је потребан резултат извршавања корутине. launch враћа Job и погодан је за fire-and-forget операције, async враћа Deferred и користи се за задатке који враћају податке. По синтакси и параметрима градитељи су идентични.
Важно правило: never use async for fire-and-forget. Ако резултат корутине није потребан, користите launch. async ствара додатни трошак за стварање Deferred, који у таквом сценарију није оправдан.
У Android-у async се користи за паралелне операције унутар ViewModel и UseCases. Типични сценарији: истовремено учитавање профила и вијести, добијање времена са више метео сервиса, пакетна синхронизација података са сервером.
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 }
}
}
}
Препоручује се умотавање групе async у coroutineScope или supervisorScope ради изолације грешака. supervisorScope омогућава наставак извршавања осталих async корутина чак и при грешци у једној од њих — корисно за некритичне операције.
Често постављана питања
Може, али бесмислено. async без await() покреће корутину, али њен резултат се губи. Ако резултат није потребан, користите launch — он не ствара Deferred и ефикаснији је по меморији и перформансама.
Изузетак унутар async се чува у Deferred. Позив await() преноси овај изузетак. За провјеру без преношења користите getCompletionExceptionOrNull(). При коришћењу coroutineScope грешка отказује све подређене корутине.
awaitAll() — функција проширења за Iterable<Deferred<T>> која зауставља корутину док се не заврше сви Deferred. Враћа листу резултата. Ако се барем један Deferred заврши са грешком, преноси изузетак и отказује остале.
Да. async — функција проширења CoroutineScope, везана за scope. GlobalScope.async ствара корутину без повезивања са животним циклусом — може се извршавати бесконачно. У Android-у GlobalScope се не препоручује због ризика од цурења меморије.
Број диктира диспечер: Dispatchers.IO подржава до 64 истовремене нити, Dispatchers.Default — по броју CPU језгара. За масовне операције користите ограничени паралелизам преко Semaphore или mapNotNull са awaitAll.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође