Kotlin coroutines یک راه بسیار عالی برای نوشتن کد به شکل غیر همزمان (asynchronous) است که کاملا خوانا و راحت است. کاتلین با یک ساختار بسیار ساده کاتلین کوروتین را ارائه میدهد: کلمه کلیدی
در این پست قصد داریم اصول کوروتینها و توابع suspend را به شما یاد دهیم. البته قبل از اینکه آموزش coroutines در کاتلین را به صورت کدی آغاز کنیم، بهتر است با مفهوم کروتینز آشنا شویم. با ما همراه باشید.
ممکن است به مطالب زیر علاقهمند باشید:
- مقایسه فلاتر با KMM (کاتلین مولتی پلتفرم موبایل)
- فایربیس چیست؟ استفاده از فایربیس در ایران
- آموزش Koin؛ کاتلین کوین چیست؟
فهرست مطالب
Kotlin coroutines چیست؟
کوروتین در کاتلین 1.1 معرفی شد. کاتلین یک روش جدید برای برنامهنویسی ناهمزمان و غیر متوقف شونده (non-blocking) معرفی کرد. یک کد ناهمزمان (asynchronous) کدی است که به صورت موازی اجرا میشود. همچنین به آن non-blocking نیز میگویند زیرا در نتیجه استفاده از آن باعث میشود که نخ اصلی اپلیکیشن (Main Thread) متوقف نشود. در حالت همزمان کدها به صورت خط به خط اجرا میشوند.
فرض کنید برنامه شما به یک خط رسیده است که باید اطلاعاتی را از بستر اینترنت دریافت کند. سرعت اینترنت شما ممکن است پایین باشد و یا زمان زیادی نیاز شود که اپلیکیشن منتظر دریافت پاسخ از سرور شود. چه اتفاقی برای برنامه شما خواهد افتاد؟ برنامه شما قفل میشود و حتی ممکن است رابط کاربری (UI) که وظیفه تعامل با کاربر را دارد نیز قفل شود و یا در بهترین حالت لگی شود. راهکار این مشکل چیست؟ برای جلوگیری از عدم اتفاق چنین مشکلی، درخواست به سرور را به صورت موازی با برنامه اصلی اجرا میکنند. مزیت اصلی آن این است که از فرآیند اصلی برنامه شما جدا میشود و به صورت جداگانه کار خود را انجام میدهد. ما نیز هر زمان که به پاسخ رسید، میتوانیم در فرآیند اصلی برنامه نتیجه را نمایش دهیم.
چرا باید از کوروتینز در کاتلین استفاده کنیم؟
همانگونه که احتمالا شما نیز میدانید، در زبان جاوا و برنامهنویسی اندروید، روشهای بسیاری برای برنامهنویسی موازی یا Async وجود دارد. میتوانید از Thread، AsyncTask، Rxjava و... استفاده کنید. پس چرا باید از کوروتینز استفاده کنید؟
اگر از Rxjava استفاده کرده باشید، احتمالا میدانید که زمان زیادی را باید بگذارید تا بتوانید به تجربه کافی برای استفاده بدون مشکل و امن از آن برسید. AsyncTask نیز ابزاری است که فقط برای کارهای کم حجم کاربرد دارد و نمیتوان از آن برای کارهای زمانبر و نسبتا حجیم استفاده کرد. Thread نیز مسائلی مثل مشکلات حافظه و کمبود آن را دارد. از اینها نیز بگذریم، کدهای این ابزارها احتمالا چندان خوشایند نیست و همچنان که از Callbackهای بیشتری استفاده کنید، کدهای شما ظاهری زشتتر را به خود خواهند دید و این شما را حتما آزرده خاطر خواهد کرد.
بعد از اولین تست کاتلین کوروتین، نظر شما درباره همه چیز تغییر خواهد کرد و از کار با آن لذت خواهید برد. کاتلین کوروتین بسیار سبک است و کار با آن بسیار آسان است. از این ابزار در بسیاری از فریمورکها مانند فریمورک Ktor استفاده شده است (این فریمورک بر اساس این ابزار توسط Jetbrains توسعه داده شده است). گوگل نیز برای توسعه UI اندروید با Jetpack Compose از این قابلیت استفاده میکند و دلیل آن نیز سبک بودن و سادگی استفاده بیان شده است.
معمولا در زبانهای برنامهنویسی برای اینکه به صورت موازی یک کد را اجرا کنند، از Thread استفاده میشود اما چیزی که کاتلین معرفی کرده، شبیه Thread عمل میکند اما Thread نیست! زیرا ممکن است چندین جاب از coroutine در یک ترد اجرا شوند و ترد جدیدی برای هر کدام ساخته نشود. همچنین اجرای بیش از حد تردها و انجام کار موازی ممکن است در نهایت به ایجاد مشکل در پاسخگویی دستگاه شود اما coroutine باعث ایجاد چنین مشکلی در صورتی که حجم کار نیز سنگین باشد، نمیشود و حافظه را بسیار بهتر مدیریت میکند. آیا زبانهای دیگر چنین قابلیتی را مثل کاتلین تعبیه کردهاند؟ تا کنون من که ندیدهام. حقیقتا بسیار تاثیر برانگیز است.
پیشنیازهای استفاده از Coroutines
- نصب یکی از IDEهای اندروید استودیو یا IntelliJ IDEA
- داشتن دانش اصولی برنامهنویسی به زبان کاتلین (اگر برنامهنویسی به زبان کاتلین را شروع نکردهاید، بهترین دوره آموزش کاتلین را از استک لرن شروع کنید)
شاید این دوره مناسب شما باشد: دوره آموزش رایگان اندروید استودیو با کاتلین
نصب Coroutines در کاتلین به کمک Dependency
برای نصب Coroutines در کاتلین باید این وابستگی (dependency) را به پروژه خود اضافه کنید.
برای نصب coroutines در اندروید این وابستگی را نیز اضافه کنید:
اولین مثال از Coroutine
همانطور که گفته شد، یک کوروتین نوعی Suspend است و تقریبا شبیه ترد است اما در واقع ترد نیست و به یک ترد محسور نمیشود. ممکن است یک کروتین در یک ترد مکث کند ولی در تردی دیگر دوباره از سر گرفته شود. برای فهم بهتر آن، یک کوروتین را از نظر کارایی به شکل یک ترد ببینید اما بدانید که یکی نیستند و تفاوتهای بنیادینی با هم دارند.به کد زیر دقت کنید:
خروجی کد بالا به این شکل است:
Hello
World!
حال بگذارید کد بالا را با هم تحلیل کنیم.
launch یک سازنده coroutine است و همزمان با بقیه کد به صورت موازی اجرا میشود ولی به صورت مستقل و مجرا. به همین دلیل ابتدا Hello اجرا شد.
delay یک متد ویژه برای ایجاد تاخیر در اجرا به اندازه یک زمان مشخص است. ذکر این نکته حائز اهمیت است که delay بقیه کوروتینها در ترد را متوقف نمیکند. فقط همان کوروتین متوقف میشود و اگر در همان ترد تعداد دیگری کروتین در حال اجرا باشند، بدون ایجاد خللی در آنها به کار خود ادامه میدهند.
runBlocking هم یک سازنده coroutine است که یک پلی بین کروتین وfun main() میباشد. به این معنا که در اینجا میتوانید کدهای دو دنیای اپ اصلی و کروتین را بنویسید و ارتباط آنها را با هم تشکیل دهید (همانندrunOnUIThread در اندروید). اگر runBlocking را حذف کنید، یک ارور در launch دریافت خواهید کرد. زیرا launch فقط باید در یک CoroutineScope تعریف شود.
تابع Suspend در Coroutine
همان کد بالا را در نظر بگیرید. بگذارید تمام کدهای درون
بنابراین همان کد قبلی ما به شکل زیر خواهد شد:
سازنده Scope در Coroutine
این قابلیت وجود دارد که Scope خودتان را به کمک
شما میتوانید از coroutineScope در هر تابعی از suspend استفاده کنید. برای مثال میتوانید کد قبل را به این شکل نیز بنویسید:
همزمانی و سازنده Scope
یک سازنده
هر دو کروتین در یک
Hello
World 1
World2
Done
جاب (Job) در Coroutine
یک سازنده کروتین launch یک Job را برمیگرداند و در واقع یک هندلی برای کروتین است و میتواند تا زمان اجرای کامل خود صبر کند. برای مثال میتوانید منتظر اجرای فرزند باشید و سپس Done را چاپ کنید:
خروجی کد بالا این است:
Hello
World!
Done
کروتینها سبک هستند
کد زیر را اجرا کنید:
این کد صد هزار کروتین را اجرا میکند و پس از 5 ثانیه هر کروتین یک نقطه را چاپ میکند. کافیست برای مقایسه Thread با Coroutine، کد runBlocking را حذف کنید و به جای launch، از thread استفاده کنید. به جای delay نیز Thread.sleep را قرار دهید. چه اتفاقی خواهد افتاد؟ به نظر تنها یک اتفاق محتمل است و آن نیز کمبود حافظه است اما کروتینها به راحتی این گونه مسائل را مدیریت خواهند کرد و از حافظه به خوبی استفاده میکنند. تاثیر برانگیز است نه؟ ساده و کم حجم!