Coroutines (کوروتینها) — نخهای سبک Kotlin برای برنامهنویسی ناهمزمان هستند که از طریق کتابخانه kotlinx.coroutines در دسترس هستند. به گزارش JetBrains Kotlin Documentation, 2026، Coroutines امکان توقف اجرای تابع بدون مسدود کردن نخ را فراهم میکنند، برخلاف Threadهای سنتی. کوروتینها روی یک استخر محدود از نخها اجرا میشوند که آنها را هزاران بار سبکتر از نخهای بومی میکند. Kotlin Coroutines به طور کامل با Android Jetpack، Retrofit، Room و سایر کتابخانههای محبوب اکوسیستم Android یکپارچه شدهاند.
نکات کلیدی
Coroutines (کوروتینها) — مکانیزم برنامهنویسی ناهمزمان در Kotlin هستند که در کتابخانه kotlinx.coroutines پیادهسازی شدهاند. برخلاف نخهای سیستم عامل، کوروتینها به یک نخ خاص متصل نیستند: آنها میتوانند روی یک نخ متوقف شده و روی نخ دیگر از سر گرفته شوند. یک نخ میتواند هزاران کوروتین را با حداقل سربار جابجایی بین آنها اجرا کند.
کوروتینها در Kotlin 1.3 (2018) به عنوان یک ویژگی آزمایشی ظاهر شدند و در Kotlin 1.5 (2021) پایدار شدند. Coroutines مشکل callback hell را مشابه async/await حل میکنند، اما API غنیتری ارائه میدهند: کانالها (Channel)، Flow، مدیریت استثنا در سلسلهمراتب Job و یکپارچگی مستقیم با Android Lifecycle.
به گزارش JetBrains (2025)، هر کوروتین حدود 100 بایت حافظه مصرف میکند در مقابل 1+ مگابایت برای یک نخ بومی. این امکان اجرای میلیونها کوروتین در یک برنامه را بدون خطر OutOfMemoryError فراهم میکند. دقیقاً سبکی کوروتینها آنها را به ابزار ترجیحی برای ناهمزمانی در Android تبدیل میکند.
هر کوروتین Kotlin از طریق Continuation Passing Style (CPS) به یک ماشین حالت کامپایل میشود. کامپایلر یک پارامتر مخفی Continuation به هر تابع suspend اضافه میکند. Continuation شامل نقطه از سرگیری و تمام متغیرهای محلی است. وقتی کوروتین متوقف میشود، runtime Continuation را ذخیره میکند و وقتی از سر گرفته میشود، آن را روی هر نخ موجود از استخر Dispatcher بازیابی میکند.
suspend — کلمه کلیدی Kotlin است که یک تابع را به عنوان قابل توقف علامتگذاری میکند. چنین تابعی را فقط میتوان از یک تابع suspend دیگر یا از یک کوروتین فراخوانی کرد. درون یک تابع suspend میتوان توابع suspend دیگر را به هر ترتیبی فراخوانی کرد، و هر نقطه فراخوانی یک نقطه توقف بالقوه است.
مکانیک ساده است: وقتی یک تابع suspend تابع suspend دیگری را فراخوانی میکند، در آن نقطه متوقف میشود و نخ را آزاد میکند. پس از اتمام تابع فراخوانیشده، runtime اجرا را از مکان ذخیرهشده ادامه میدهد. به این cooperative cancellation میگویند — هیچ نخی مسدود نمیشود.
مهم: تابع suspend به طور پیشفرض ناهمزمان نیست. ترتیب اجرا تا زمانی که از launch یا async استفاده نشود، ترتیبی باقی میماند. suspend فقط به تابع اجازه میدهد بدون مسدود کردن نخ متوقف شود و بخشی از زمینه کوروتین باشد. Continuation Passing Style یک مدل کامپایل است که در آن هر تابع suspend یک callback مخفی Continuation دریافت میکند و کامپایلر یک ماشین حالت برای مدیریت توقفها و ازسرگیریها تولید میکند.
CoroutineScope — زمینهای است که چرخه حیات کوروتینها را تعیین میکند. همه کوروتینها باید درون یک scope راهاندازی شوند. وقتی scope لغو میشود (مثلاً هنگام پایان Activity)، تمام کوروتینهای فرزند آن به طور خودکار لغو میشوند. این کار از نشت وظایف پسزمینه جلوگیری میکند. Android Jetpack scopeهای آمادهای برای هر کامپوننت فراهم میکند: viewModelScope برای ViewModel و lifecycleScope برای Activity و Fragment که با نابودی کامپوننت مربوطه به طور خودکار لغو میشوند.
Structured Concurrency — اصلی که تضمین میکند کوروتین تا زمانی که تمام کوروتینهای فرزندش کامل نشدهاند، پایان نمییابد. سلسلهمراتب Job یک درخت تشکیل میدهد: کوروتین ریشه یک parent job ایجاد میکند، فرزندان child jobs ایجاد میکنند. لغو parent job به همه فرزندان سرایت میکند. Structured Concurrency تفاوت اساسی بین کوروتینها و نخها است.
| Scope | محل استفاده | لغو |
|---|---|---|
| GlobalScope | فقط برای وظایف daemon | به طور خودکار لغو نمیشود |
| viewModelScope | Android ViewModel | هنگام پاکسازی ViewModel |
| lifecycleScope | Android Activity/Fragment | هنگام نابودی lifecycle |
| coroutineScope | درون تابع suspend | هنگام لغو job والد |
Job معمولی هنگام خطای یک کوروتین فرزند، تمام siblings را لغو میکند. SupervisorJob یک استثناست: خرابی در یک کوروتین فرزند روی بقیه تأثیر نمیگذارد. این زمانی مهم است که چندین وظیفه مستقل به صورت موازی اجرا میشوند و یکی ممکن است بدون نیاز به لغو بقیه شکست بخورد.
Dispatchers تعیین میکنند کوروتینها روی کدام نخها اجرا شوند. Dispatchers.Main — نخ اصلی UI اندروید. Dispatchers.IO — استخر برای عملیاتهای مسدودکننده (شبکه، دیسک). Dispatchers.Default — برای وظایف CPU-intensive. Dispatchers.Unconfined — در نخ جاری شروع میشود اما تضمینی برای ماندن روی آن ندارد. انتخاب Dispatcher مناسب برای کارایی حیاتی است: وظیفه IO روی Default استخر را برای محاسبات مسدود میکند و وظیفه CPU روی IO نخهای اضافی ایجاد میکند.
withContext — تابعی برای تغییر Dispatcher درون کوروتین. مثلاً یک تابع suspend که JSON را تجزیه میکند میتواند حین محاسبه به Dispatchers.Default سوئیچ کند و برای بهروزرسانی UI به Dispatchers.Main برگردد. withContext پراستفادهترین سازنده در توسعه Android است.
launch — کوروتین را راهاندازی میکند، Job برمیگرداند، نتیجه برنمیگرداند (fire-and-forget). async — کوروتین را راهاندازی میکند، Deferred برمیگرداند که نتیجه از طریق await قابل دریافت است. runBlocking — نخ جاری را برای اجرای کوروتین مسدود میکند (فقط برای تستها و توابع main). انتخاب سازنده به سناریو بستگی دارد: launch برای رویدادها و بهروزرسانیها، async برای وظایف با نتیجه، runBlocking فقط برای تستها یا نقاط ورود مناسب است.
سه سناریوی عملی را بررسی میکنیم: کوروتین پایه با launch، فراخوانی موازی با async و مدیریت خطا با SupervisorJob.
viewModelScope.launch کوروتین را در زمینه ViewModel راهاندازی میکند. هنگام پاکسازی ViewModel کوروتین به طور خودکار لغو میشود.
class ProfileViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch(Dispatchers.IO) {
val user = api.fetchUser()
withContext(Dispatchers.Main) {
showUser(user)
}
}
}
}
coroutineScope با async سه درخواست را به صورت موازی راهاندازی میکند. نتایج از طریق .await() جمعآوری میشوند. اگر هر یک از درخواستها شکست بخورد، همه لغو میشوند.
suspend fun loadDashboard(): Dashboard = coroutineScope {
val user = async { api.fetchUser() }
val posts = async { api.fetchPosts() }
val stats = async { api.fetchStats() }
Dashboard(user.await(), posts.await(), stats.await())
}
SupervisorJob به هر کوروتین اجازه میدهد مستقل پایان یابد. خطا در یک درخواست بقیه را لغو نمیکند.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
try { api.fetchPosts() } catch (e: Exception) { log(e) }
}
نخها (Thread) — ابتدایی سیستم عامل هستند. هر نخ پشته مخصوص خود (~1 مگابایت) دارد و برای ایجاد و جابجایی نیاز به فراخوانی سیستم دارد. کوروتینها — ابتدایی زبان هستند که به سیستم عامل وابسته نیستند. آنها از Continuation برای ذخیره وضعیت استفاده میکنند و در سطح runtime بدون فراخوانی سیستم جابجا میشوند.
به گزارش Google (2025)، استفاده از کوروتینها به جای نخها مصرف حافظه را برای وظایف پسزمینه در برنامههای Android تا 90–95٪ کاهش میدهد. تمام کتابخانههای مدرن Android (Retrofit, Room, WorkManager) پشتیبانی داخلی از کوروتینها را از طریق توابع suspend دارند. Ktor (چارچوب HTTP کلاینت JetBrains) نیز کاملاً روی کوروتینها ساخته شده است و برای هر درخواست بدون API callback توابع suspend ارائه میدهد. Room از کوروتینها از طریق توابع suspend در DAO پشتیبانی میکند که امکان اجرای پرسوجوهای پایگاه داده بدون مسدود کردن نخ اصلی را فراهم میکند.
نخها برای کد بومی از طریق JNI، فراخوانیهای مسدودکننده CPU-intensive بدون محدودیت زمانی (رندر ویدئو، شبیهسازیها) و یکپارچگی با کتابخانههای C ضروری باقی میمانند. برای بقیه موارد — کوروتینها.
سوالات متداول
کوروتین — یک واحد کار قابل توقف است که روی یک نخ موجود اجرا میشود. نخ یک منبع سیستمی با پشته مخصوص خود است. کوروتینها هزاران بار سبکتر از نخها هستند و هنگام توقف منابع را مسدود نمیکنند.
Dispatchers.IO برای عملیاتهای I/O مسدودکننده (شبکه، فایلها) طراحی شده و میتواند در صورت نیاز نخهای جدید ایجاد کند. Dispatchers.Default استخری با اندازه ثابت (تعداد هستههای پردازنده) برای محاسبات CPU-intensive دارد.
Job.cancel() کوروتین و تمام فرزندانش را لغو میکند. برای بررسی لغو درون کوروتین از ensureActive() استفاده کنید — اگر کوروتین لغو شده باشد CancellationException پرتاب میکند.
بله — از طریق کتابخانه kotlinx-coroutines-rx3. توابع awaitSingle، awaitFirst و دیگر توابع را برای تبدیل Observable/Single به توابع suspend و بالعکس از طریق flowable ارائه میدهد.
Flow — یک جریان داده ناهمزمان سرد، مشابه Observable در RxJava برای کوروتینها است. Flow مقادیر را به صورت ترتیبی منتشر میکند و با استثنا یا موفقیت پایان مییابد. از عملگرهای map، filter، catch و دیگر عملگرها پشتیبانی میکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید