در دنیای برنامه‌نویسی اندروید و کاتلین، مدیریت عملیات ناهمزمان (Asynchronous) همیشه یک چالش بزرگ بوده است. فرض کنید اپلیکیشن شما باید همزمان چندین کار را انجام دهد: دانلود فایل، دریافت داده از سرور و پردازش‌های سنگین. استفاده از روش‌های سنتی مانند Thread می‌تواند منجر به پیچیدگی‌های زیادی از جمله سختی در مدیریت منابع و خوانایی کد شود. اینجاست که کوروتین (Coroutine) به‌عنوان یک راه‌حل مدرن و بهینه معرفی می‌شود. اما کوروتین چیست؟ در این مقاله از سری مقالات آموزش کاتلین در دانشجویار، به‌طور جامع با مفهوم کوروتین، ساختار و کاربردهای عملی آن آشنا خواهیم شد.

دوره پیشنهادی

کوروتین چیست؟ (Coroutine)

کوروتین‌ها (Coroutines) ابزاری قدرتمند در زبان برنامه‌نویسی کاتلین هستند که به شما امکان می‌دهند کدهای ناهمگام (asynchronous) را به صورت ساده‌تر و خواناتری بنویسید. در واقع، کوروتین‌ها بخش‌های سبکی از کد هستند که می‌توانند به صورت مستقل اجرا شوند و در هر زمانی معلق شده و دوباره از همان نقطه ادامه یابند.

در واقع، کوروتین‌ها در کاتلین، مانند یک دستیار خیلی زرنگ هستند که به برنامه‌نویس‌ها کمک می‌کنند تا کارهایی که زمان زیادی می‌برند (مثل دانلود یک فایل بزرگ یا گرفتن اطلاعات از اینترنت) را به صورت منظم و کارآمد انجام دهند. وقتی یک برنامه نیاز به انجام کارهای زمان‌بر دارد، کوروتین‌ها این کارها را به بخش‌های کوچکتر تقسیم می‌کنند و هر بخش را به صورت جداگانه اجرا می‌کنند. به این صورت، برنامه شما منتظر تمام شدن یک کار نمی‌ماند و می‌تواند همزمان کارهای دیگر را هم انجام دهد.

Coroutine در کاتلین

در زبان برنامه‌نویسی کاتلین، کوروتین‌ها به صورت بومی پشتیبانی می‌شوند و به شما این امکان را می‌دهند که عملیات‌های طولانی و پیچیده را بدون مسدود کردن رشته اصلی اجرا کنید. این قابلیت به خصوص برای برنامه‌نویسی موبایل و وب بسیار مفید است، زیرا می‌تواند کارایی و پاسخگویی برنامه‌ها را بهبود ببخشد.

در کاتلین، کوروتین‌ها با استفاده از کتابخانه kotlinx.coroutines پیاده‌سازی می‌شوند. این کتابخانه، ابزارها و توابع لازم برای ایجاد، مدیریت و اجرای کوروتین‌ها را فراهم می‌کند. برای استفاده از کوروتین‌ها، ابتدا باید این کتابخانه را به پروژه خود اضافه کنید. سپس می‌توانید با استفاده از کلمات کلیدی مانند launch و async کوروتین‌های جدید ایجاد کنید.

مثال ساده از کوروتین در کاتلین

*import kotlinx.coroutines.
fun main() = runBlocking {
launch {
delay(1000L)
println(“World!”)
}
println(“Hello,”)
}

در این مثال، ما از تابع launch برای ایجاد یک کوروتین جدید استفاده کرده‌ایم که پس از یک ثانیه “World!” را چاپ می‌کند. تابع runBlocking مسدود می‌شود تا زمانی که کوروتین تمام شود و سپس “Hello,” چاپ می‌شود. این مثال ساده به ما نشان می‌دهد که چگونه می‌توانیم از کوروتین‌ها برای انجام کارهای غیرهمزمان استفاده کنیم.

ترد (Thread) چیست؟

برای درک بهتر مفهوم ترد به این مثال توجه کنید. فرض کنید یک برنامه ویرایش متن دارید. این برنامه می‌تواند چندین کار را به طور همزمان انجام دهد، مانند تایپ متن، بررسی غلط املایی و ذخیره فایل. هر یک از این کارها می تواند توسط یک ترد (Thread) جداگانه انجام شود. در واقع ترد یا نخ در دنیای برنامه نویسی واحد کوچکی از پردازش است که می تواند به طور مستقل توسط سیستم عامل اجرا شود. تردها می توانند به طور همزمان اجرا شوند که این باعث می‌شود برنامه‌ها بتوانند چندین کار را به صورت موازی انجام دهند.

چرا باید از Coroutine در کاتلین استفاده کنیم؟

کاتلین اولین زبانی است که استفاده از کوروتینز را پیاده سازی کرد. زبان کاتلین قصد داشت که از همان ابتدا تمام پیچیدگی‌ها را ساده کند. فرض کنید شما در اپلیکیشن خود می خواهید برای دریافت یک فایل از اینترنت، یک ترد ایجاد کنید و در کنار آن یک فایل هم در دیتابیس خود بسازید، به‌علاوه یک عملیات ریاضی سنگین هم انجام دهید. اگر برای هر کدام از این کارها یک ترد جداگانه بسازید، تعداد تردها زیاد و مدیریت آن‌ها پیچیده می‌شود، که ممکن است به کرش شدن اپلیکیشن منجر شود.

کاتلین کروتینز پیاده‌سازی شد تا بتوان برنامه نویسی ناهمزمان (Asnchronous) را بهتر انجام داد و به جای ایجاد تردهای متعدد، چندین کوروتین را در یک ترد واحد اجرا کرد. یعنی در پس‌زمینه، یک ترد واحد برای اجرای تعداد زیادی کوروتین و جاب (Job) استفاده شود، بدون اینکه منابع سیستم به‌طور غیرمؤثر مصرف شوند. به این ترتیب، بدون نگرانی از کرش شدن برنامه یا کمبود حافظه، می‌توان هزاران کار را به‌طور همزمان اجرا کرد.

ساختار اصلی کوروتین در کاتلین

ساختار کوروتین در کاتلین

برای استفاده از کوروتین‌ها در کاتلین، ابتدا باید کتابخانه kotlinx.coroutines را به پروژه خود اضافه کنید. این کتابخانه مجموعه‌ای از توابع و کلاس‌ها را برای برای کار با کوروتین‌ها و مدیریت برنامه‌نویسی ناهمزمان (Asynchronous) فراهم می‌کند.

✅ توابع معلق (suspend)

توابع معلق قلب اصلی کوروتین‌ها هستند. این توابع به شما این امکان را می دهند که یک عملیات طولانی را اجرا کنید و بدون مسدود کردن رشته اصلی در جای مورد نیاز متوقف شوید.

✅ دامنه کوروتین (CoroutineScope)

همه کوروتین‌ها داخل یک Scope یا دامنه ایجاد می شوند. دامنه‌ها برای مدیریت عمر کوروتین‌ها استفاده می شوند. نمونه هایی از این دامنه‌ها عبارتند از:

  • GlobalScope: کوروتین‌های سطح بالا که تا پایان اجرای برنامه فعال می‌مانند.
  • CoroutineScope: مدیریت محلی‌تر و قابل کنترل‌تر کوروتین‌ها.
  • runBlocking: مسدود کردن رشته فعلی برای اجرای کوروتین.

✅ launch و async

تابع launch برای اجرای عملیات غیرهمزمان که نتیجه‌ای باز نمی‌گرداند. async برای اجرای عملیات غیر همزمان که یک مقدار باز می گرداند.

✅ تعیین نخ اجرا (Dispatcher)

Dispatcher تعیین می‌کند که کوروتین در کدام نخ اجرا شود. کاتلین Dispatcher‌های مختلفی را ارائه می‌دهد که می‌توانید بر اساس نیاز از آنها استفاده کنید. برخی از مهم‌ترین انواع آن عبارتند از:

  • Dispatchers.Main: اجرای روی ترد اصلی (UI) (مناسب برای به‌روزرسانی رابط کاربری)
  • Dispatchers.IO: اجرای روی ترد مخصوص عملیات ورودی/خروجی
  • Dispatchers.Default: اجرای روی ترد مناسب برای پردازش‌های سنگین CPU

تفاوت کوروتین با RxJava ،Thread ،AsyncTask در چیست؟

اگر برای هر عملیاتی یک ترد مجزا ایجاد کنیم، تعداد زیاد تردها فشار زیادی به پردازنده وارد کرده و باعث کاهش عملکرد برنامه می‌شود. این موضوع باعث می‌شود اپلیکیشن بسته شود یا به قول معروف کرش شود. در نتیجه مدیریت تردها سخت‌تر می شود. به همین دلیل، برای پردازش‌های سبک و کوتاه‌مدت معمولاً از AsyncTask استفاده می‌شد. از سوی دیگر، RxJava اگرچه قابلیت‌های گسترده‌ای برای برنامه‌نویسی واکنشی فراهم می‌کند، اما یادگیری و استفاده از آن پیچیده بوده و تسلط بر تمام امکانات آن به زمان زیادی نیاز دارد.

در صورتی که هر گونه سوال یا ابهامی در مورد مقاله کوروتین چیست دارید، می‌توانید در بخش دیدگاه‌ها در همین صفحه مطرح نمایید.