async: چیست، Deferred و هم‌روال‌های موازی چگونه کار می‌کنند

نویسنده: IT Sectr منتشر شده: 2026-06-22 زمان مطالعه: 8 دقیقه

async — Coroutine Builder در کاتلین که یک هم‌روال را راه‌اندازی می‌کند و یک شی Deferred<T> برای دریافت نتیجه عملیات ناهمگام برمی‌گرداند. async امکان اجرای موازی چندین وظیفه و تجمیع نتایج آنها را از طریق await() فراهم می‌کند. بر اساس راهنمای JetBrains، 2024، async روش ترجیحی برای سازماندهی محاسبات موازی در هم‌روال‌ها است.

نکات اصلی

  • async — سازنده هم‌روال که Deferred<T> را با نتیجه عملیات ناهمگام برمی‌گرداند
  • Deferred — وعده ناهمگام، ارث‌برنده از Job، با متد await() برای دریافت نتیجه
  • async امکان اجرای موازی وظایف مستقل را فراهم می‌کند و زمان کل را کاهش می‌دهد
  • await() — تابع suspend که هم‌روال را تا دریافت نتیجه بدون مسدودسازی متوقف می‌کند
  • هم‌روندی ساختاریافته با async لغو تمام وظایف موازی را در صورت خطا تضمین می‌کند

async در کاتلین کوروتینز چیست؟

async — یک تابع توسعه‌دهنده CoroutineScope است که یک هم‌روال با قابلیت بازگرداندن نتیجه ایجاد می‌کند. برخلاف launch، async یک Deferred<T> — شیئی که یک مقدار آینده را نشان می‌دهد — برمی‌گرداند. هم‌روال راه‌اندازی شده از طریق async به صورت هم‌روند با سایر هم‌روال‌ها اجرا می‌شود که امکان موازی‌سازی محاسبات را فراهم می‌کند.

async زمانی استفاده می‌شود که نتیجه عملیات ناهمگام برای پردازش بعدی مورد نیاز است: بارگذاری داده از چندین منبع، پردازش دسته‌ای مجموعه‌ها، درخواست‌های موازی به APIهای مختلف. Deferred بلافاصله ایجاد می‌شود و نتیجه پس از اتمام هم‌روال در دسترس می‌شود.

kotlin
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 و Deferred

امضای async مشابه launch است: همان پارامترهای CoroutineContext، CoroutineStart و بلوک suspend. تفاوت در نوع بازگشتی است — Deferred<T> به جای Job، که در آن T نوع نتیجه‌ای است که توسط آخرین عبارت بلوک بازگردانده می‌شود.

kotlin
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 هم‌روال‌ها را همزمان راه‌اندازی می‌کند و زمان کل را به زمان طولانی‌ترین عملیات کاهش می‌دهد.

بارگذاری موازی داده

سناریوی معمول — بارگذاری پروفایل کاربر، تنظیمات و تاریخچه سفارشات با سه درخواست async موازی. پس از اتمام هر سه، نتایج در یک مدل داده واحد ترکیب می‌شوند.

kotlin
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

Deferred چندین روش برای کار با نتیجه پشتیبانی می‌کند. علاوه بر await()، روش‌هایی برای بررسی وضعیت، دریافت مقدار آماده و تجمیع چندین Deferred از طریق توابع کمکی کاتلین کوروتینز در دسترس است.

متدتوضیحاتSuspend؟
await()هم‌روال را تا دریافت نتیجه متوقف می‌کندبله
getCompleted()نتیجه را برمی‌گرداند اگر هم‌روال کامل شده باشد (در غیر این صورت Exception)خیر
getCompletionExceptionOrNull()در صورت خطا استثنا یا null را برمی‌گرداندخیر
isCompletedبررسی می‌کند که آیا هم‌روال کامل شده استخیر

برای تجمیع لیست Deferred از awaitAll() استفاده می‌شود — تابعی که اجرا را تا اتمام تمام Deferredهای موجود در مجموعه متوقف می‌کند. اگر حداقل یکی با خطا به پایان رسیده باشد، awaitAll() استثنا پرتاب می‌کند.

kotlin
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
    return coroutineScope {
        val deferreds = requests.map { async { it() } }
        deferreds.awaitAll()
    }
}

تفاوت‌های async و launch

انتخاب بین async و launch به نیاز به نتیجه اجرای هم‌روال بستگی دارد. launch Job را برمی‌گرداند و برای عملیات fire-and-forget مناسب است، async Deferred را برمی‌گرداند و برای وظایفی که داده برمی‌گردانند استفاده می‌شود. از نظر نحو و پارامترها، سازنده‌ها یکسان هستند.

  • launch → Job (بدون نتیجه)، async → Deferred<T> (نتیجه T دارد)
  • launch — وظایف fire-and-forget (ثبت رویداد، کش کردن، ارسال آمار)
  • async — محاسبات موازی (بارگذاری از چندین API، پردازش دسته‌ای)
  • هر دو از هم‌روندی ساختاریافته و پارامترهای CoroutineStart پشتیبانی می‌کنند
  • await() فقط برای Deferred در دسترس است، launch نتیجه ارائه نمی‌دهد

قانون مهم: هرگز از async برای fire-and-forget استفاده نکنید. اگر نتیجه هم‌روال مورد نیاز نیست، از launch استفاده کنید. async سربار ایجاد Deferred را تحمیل می‌کند که در چنین سناریویی توجیه‌پذیر نیست.

نمونه‌های async در توسعه موبایل

در اندروید async برای عملیات موازی داخل ViewModel و UseCases استفاده می‌شود. سناریوهای معمول: بارگذاری همزمان پروفایل و فید خبری، دریافت آب و هوا از چندین سرویس هواشناسی، همگام‌سازی دسته‌ای داده با سرور.

kotlin
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 استفاده کرد؟

می‌توان، اما بی‌معنی است. async بدون await() هم‌روال را راه‌اندازی می‌کند اما نتیجه آن از دست می‌رود. اگر نتیجه نیاز نیست، از launch استفاده کنید — Deferred ایجاد نمی‌کند و از نظر حافظه و عملکرد کارآمدتر است.

چگونه async استثناها را مدیریت می‌کند؟

استثنای داخل async در Deferred ذخیره می‌شود. فراخوانی await() این استثنا را منتقل می‌کند. برای بررسی بدون انتقال از getCompletionExceptionOrNull() استفاده کنید. هنگام استفاده از coroutineScope، خطا تمام هم‌روال‌های فرزند را لغو می‌کند.

awaitAll در کاتلین کوروتینز چیست؟

awaitAll() — یک تابع توسعه‌دهنده برای Iterable<Deferred<T>> که هم‌روال را تا اتمام تمام Deferredها متوقف می‌کند. لیست نتایج را برمی‌گرداند. اگر حداقل یک Deferred با خطا به پایان برسد، استثنا پرتاب می‌کند و بقیه را لغو می‌کند.

آیا async با GlobalScope.async تفاوت دارد؟

بله. async یک تابع توسعه‌دهنده CoroutineScope است که به scope متصل است. GlobalScope.async یک هم‌روال بدون اتصال به چرخه حیات ایجاد می‌کند — می‌تواند بی‌نهایت اجرا شود. در اندروید GlobalScope به دلیل خطر نشت حافظه توصیه نمی‌شود.

چند هم‌روال async می‌توان برای درخواست‌های موازی راه‌اندازی کرد؟

تعداد توسط توزیع‌کننده تعیین می‌شود: Dispatchers.IO تا 64 رشته همزمان را پشتیبانی می‌کند، Dispatchers.Default — بر اساس تعداد هسته‌های CPU. برای عملیات انبوه از موازی‌سازی محدود از طریق Semaphore یا mapNotNull با awaitAll استفاده کنید.

خلاصه

  • async — سازنده هم‌روال که Deferred<T> را برای دریافت نتیجه ناهمگام برمی‌گرداند
  • Deferred از Job ارث‌بری می‌کند و متدهای await()، getCompleted()، getCompletionExceptionOrNull() را اضافه می‌کند
  • اجرای موازی با async زمان کل را به مدت طولانی‌ترین عملیات کاهش می‌دهد
  • awaitAll() — ابزاری برای انتظار تمام Deferredهای موجود در مجموعه
  • coroutineScope — پوشش توصیه‌شده برای گروه async با تضمین لغو
  • از async برای fire-and-forget استفاده نکنید — launch را به کار ببرید
  • در اندروید async برای بارگذاری موازی در ViewModel با viewModelScope استفاده می‌شود

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید