با آموزش کاتلین کوروتین در خدمت شما عزیزان کدایت هستیم . شاید شما هم در طول برنامه نویسی خودتون کلمه های مانند Thread ، Async Task و Rxjava و همچنین Kotlin coroutine به گوشتان خورده باشد . ما امروز یاد خواهیم گرفت که کاتلین کوروتین چیست ؟ و چه کارایی برای ما دارد ؟ و تفاوت آن با مفاهیم مطرح شده بالا در چیست.
کاتلین کوروتین چیست ؟
اگربخواهم خیلی ساده برای شما بگویم ، کوروتین دقیقا مانند Thread عمل می کند ولی ترد نیست . از کروتین برای برنامه نویسی به صورت غیر همزمان یا همان asynchronous استفاده میشود .نگران نباشید در ادامه توضیح خواهم داد که کدنویسی همزمان و غیره همزمان چیست و چه مزایایی دارد . در ترد اصلی یا همان Main Thread ، رابط کاربری یا UI و هر چیزی که به UI ما مربوط است قرار دارد .
اگر ما بخواهیم درخواست دیگری که نسبتا هم سنگین است را در این Thread انجام دهیم .این کار Thread ما را به خود مشغول می کند و به اصطلاح main Thread ما دیگر نمیتواند رابط کاربری را برای ما نمایش دهد و برنامه ما به اصطلاح crash و مسدود میشود .
Coroutine ها از نسخه 1.3 به کاتلین اضافه شدند و از مفاهیم تثبیت شده از زبان های دیگر میباشد . نکته جالب اینجا است که طبق گزارش هایی که از توسعه دهندگان حرفه ای اندروید که از کاتلین کوروتین استفاده میکنند جمع آوری شده ، نزدیک به 50 درصد از آنها اعتقاد دارند که سطح بهروری آنها افزایش پیدا کرده است .
به چه منظوری از Kotlin Coroutine استفاده میشود
فرض کنید من یک تابع دارم که برای شبکه در Main Thread درخواست ارسال می کند . البته بزارید یه نکته هم داخل پارانتز براتون بگم (به Thread اصلی Main Thread یا UI Thread می گویند و به ترد های دیگر که در پس زمینه به صورت موازی اجرا می شوند Helper Thread میگویند .) با این کار ترد اصلی به کل مشغول میشود. و تا زمانی که درخواست شبکه ما انجام نشود کل thread اصلی مشغول هست و UI ما به درستی نمایش داده نمیشود. و این که ترد اصلی ما مشغول باشد فکر خوبی نیست .
کار درستی که ما باید انجام دهیم این است که تمامی کار ها و فعالیت های نامرتبط با UI برنامه خودمان را در یک Thread مجزای دیگر انجام دهیم . در این زمان است که کاتلین کوروتین (kotlin coroutines ) وارد عمل میشود . در واقع ما با کمک کوروتین برنامه نویسی غیر همزمان یا Asynchronous را انجام میدهیم تغییراتی که ما باید انجام شود تا از کاتلین کوروتین استفاده کنیم این هست که در پشت تابع کلمه Suspend را به کار ببریم .
کار Suspend این است که به کامپایلر کاتلین بگوید که تابع ما در یک کوروتین (Coroutines) اجرا میشود و اینکه ما یک تابع کوروتین را فقط میتوانیم از یک روال مشترک یا یک تابع Suspend دیگر فراخوانی کنیم.
نکته مهم : چندیدن کوروتین را میتوانم در یک Thread اجرا کنیم . کوروتین ها بسیار سبک تر از Thread ها هستند . و نکته خیلی مهم دیگر این است که مدیریت Thread ها به دست سیستم عامل میباشد ولی مدیریت کوروتین ها توسط کاربر انجام میگیرد . در واقع به تعریفی دیگر کوروتین ها شبیه یک Framework ای است که Thread ها را مدیریت میکند .
کد نویسی Asynchronous یا synchronous چیست ؟
کدنویسی synchronous یا همزمان یعنی زمانی که من چندین task دارم، ابتدا تسک اول انجام میشود و بعد از اینکه تمام شد task دومی شروع میگردد و به ترتیب تا آخر ادامه مییابد . ولی کدنویسی Asynchronous یا غیر همزمان اینگونه نیست و هر چند تا task که داشته باشیم به صورت موازی اجرا میشوند. و شروع Task ای نیاز به تمام شدن تسک دیگری نیست .
تفاوت کوروتین با Rxjava , Thread , AsyncTask در چیست ؟
هر کدام از اصطلاح های که در عنوان مطرح کردیم به نوبه خود ایراد های دارد . و به همین منظور نیز کاتلین کوروتین آمد تا جایگزین مناسبی برای آن ها گردد من برخی از ایرادات و مشکلات هر یک از آن ها را برای شما مطرح میکنم .
ٍRxJava : ما به عنوان برنامه نویس باید زمان خیلی زیادی بگذاریم تا به یک تجربه ای برسیم که بدون مشکلات و به صورت امن از این تکنولوژِی استفاده کنیم . بنابراین یک گزینه مناسبی نیست .
َAsyncTask : این تکنولوژی نیز برای زمانی میباشد که کار های ما دارای حجم زیاد نباشد و کلا مناسب کارهای با حجم کم است .
Thread : بزرگترین مشکل ترد ها حافظه و کمبود آن است .
ولی در مقابل kotlin coroutines بسیار سبک است و کار ما را خیلی خیلی آسان تر کرده است.
چه مشکلاتی با آمدن کاتلین کوروتین برطرف شده است؟
- با وجود کاتلین کوروتین دیگر در UI Theard یا Main Thread کار های طولانی مدت انجام نمیشود و کوروتین آنها را مسدود میکند.
- و مشکل دیگر که حل شده است این میباشد که ما میتوانیم تابع Suspend را در Thread اصلی صدا بزنیم
- در واقع کوروتین کد های مارا ساده میکند تا ما بتوانیم کارهای طولانی مدت را به راحتی مدیریت کنیم .
مطالب پربازدید:زبان کاتلین چه ویژگی هایی دارد ؟
Coroutine دارای ویژگی های است
Lightweight : به دلیل پشتیبانی از Suspend ها میتوانیم بسیاری از Coroutine ها را در یک رشته اجرا کنید. که این امر باعث مسدود شدن رشته ای که کوروتین روی آن درحال اجرا است نمیگردد.
Fewer Memory Leaks : از همزمانی ساخت یافته برای اجرای عملیات در یک Scope استفاده میشود.
یک پارچه سازی Jetpack : بسیاری از کتابخانه های Jetpack دارای برنامه های افزودنی است که پشتیبانی کامل از کوروتین را ارائه میکنند.برخی از کتابخانه ها هم محدوده کاری خود را ارائه میدهند که میتوانیم از آن برای همزمانی ساختار یافته استفاده کنید.
کوروتین اسکوپ هایی که در کاتلین مورد استفاده قرار میگیرد
Global scope :این Scope به طول عمر یا lifetime هیج شی یا فعالیتی وابسته نیست . یک محدوده پیش فرض میباشد برای زمانی که ما میخواهیم یک کوروتین را راه اندازی کنیم . Global scope حتی پس از تکمیل بلوک سازنده کوروتین همچنان اجرا میشود و توسط سیستم لغو نمیگردد مگر اینکه به صورت مستقیم لغو کنیم . و یا با خاتمه زمینه کاری که در آن اجرا میشود.
LifeCycle scope :یک اسکوپی است که به Lifecycle هر Object یا فعالیتی مانند Activity و یا Fragment وابسته میباشد. و زمانی که این فعالیت از بین میرود ، این Scope نیز به صورت خودکار لغو میشود.این کار برای زمانی است که ما میخواهیم کلیه کار هایی که در پس زمینه اجرا میشود وکاربر نیز برای مدتی از آن دور شده را لغو کنیم .
Viewmodel scope :این اسکوپی میباشد که به Lifecycle ویو مدل گره خورده است . زمانی که Viewmodel از بین میرود آن برنامه هایی که در این Scope راه اندازی شده است به طور خودکار لغو میباشد . وقتی که کاربر از رابط کاربری دور بماند ودیگر قابل مشاهده نباشد . این کار برای لغو کار های background جاری مفید است .
Coroutine builders چیست ؟
همانطور که از اسمش معلوم است کوروتین بیلدیر ها یک روش مناسب برای ساخت کوروتین است . و به دلیل اینکه خودشان را Suspend نمیکنند میتوان آنها را از کد های غیره Suspend یا هر قطعه کد دیگر فراخوانی کرد .درواقع Coroutine Builder ها مانند یک لینک بین بخش های Suspend وغیره Suspend کد ما عمل میکنند. و اما کاتلین کوروتین بیلدیر های معروف به شرح زیر است .
runblocking : همان طور که از اسم آن مشخص میباشد یک Coroutine Builder ای است که رشته فعلی را مسدود میکند.تا زمانی که تمامی وظایف کاری تمام شود . اینجا سوالی پیش می آید و آن هم این است که زمانی که ما به طور واضح نمیخواهیم Thread خودمان را مسدود کنیم چرا از runBlocking باید استفاده کنیم؟
ما معمولا blocking را انجام میدهیم تا تست هایی که روی تابع Suspend اجرا کنیم، ما میخواهیم مطمعن شویم زمانی که در حال انجام کارهای سنگین در عملگر های تست Suspend هستیم ، تست را تمام نکنیم .
Launch : یک کوروتین جدید را راه اندازی میکند بدون اینکه نتیجه ای را برای Caller برگرداند . و همچنین اجازه میدهد تا یک کوروتین در پس زمینه شروع کنیم
async : واما یکی از بهترین Coroutine Builder ها Async میباشد . یک کوروتین بیلدیرایی میباشد که یک مقدار را به Caller برمیگرداند . و ما میتوانیم از Async استفاده کنیم و یک کوروتین ایجاد کنیم و کار های سنگین خودمون را روی آن انجام دهیم . و نکته دیگر این است که زمانی که شما نیازی ندارید به اینکه چیزی برای Caller برگردانید پس نیاز نیست که از آن استفاده کنیم .
نکته : delay در کاتلین یک تابع Suspend است که بدون این که thread اصلی ما را مسدود کند یک کوروتین را به تاخیر می اندازد . و بعد از یک مدت زمان مشخص(مثال:3000L)کار روتین را از سر میگیرد.
به چه دلیل نباید از Global Scope استفاده کرد؟
دلیل این کار این است که Global Scope کوروتین های سراسری یا همان Global ایجاد میکند که در هیچ دامنه ای قرار ندارند . به همین دلیل این وظیفه برگردن خود برنامه نویس میافتد که کوروتین را بررسی کند و بعد از اینکه کار کوروتین ها تمام شد آنها را نابود کند . به طور کلی اگر نتوانیم به درستی از آن استفاده کنیم باعث نشت حافظه میشود.
نکته 1 : اسناد رسمی میگوید که کوروتین ها thread ها Light weight هستند . این وزن سبک به این معنی است که ایجاد کوروتین ها موضوعات جدید را اختصاص نمیدهد.
نکته 2 : کوروتین ها Thread های سبک وزنی هستند که mainThread را مسدود نمیکنند. ولی در عین حال امکان فراخوانی تابع Suspend را در main Threadرا فراهم میکند.
نکته 3: تابع Suspend ، تابعی است که قابلیت تعلیق اجرای کوروتین فعلی را بدون مسدود کردن Thread ای که در جریان هست را دارد . همچنین این تابع میتواند در نقطه ای ، اجرا را از سر بگیرد. همچنین ویژگی تعلیق تابع Suspend به ما کمک میکند تا کدهای ناهمزمان را به صورت همزمان بنویسیم.
نکته 4 : نکته مهم دیگر این است که تابع های Suspend خود غیرهمزمان یا Asynchrouns نیستند.
Dispatchers یا توزیع کننده درkotlin coroutines چیست ؟
Dispatcher یا توزیع کننده یک قابلیت ضروری است برای تصمیم گیری در مورد اجرای کوروتین ها در روی Thread های مختلف:
انواع Dispatcher :
بسته به کاری که کوروتین قرار است انجام دهد. چهار نوع Dispatchers وجود دارد:
- توزیع کننده Default
- توزیع کننده Main
- توزیع کننده IO
- توزیع کننده Unconfined
- دیسپچر پیش فرض برای زمانی میباشد که یکسری توابع سنگین در CPU انجام میدهیم . اگر فراموش کنیم که ِDispatvher خودتون را انتخاب کنیم، این توزیع کننده به طور پیش فرض انتخاب می شود. و اما syntax آن نیز به شکل زیر میباشد .
launch(Dispatchers.Default)
- این توزیع کننده زیاد استفاده نمی شود. فقط زمانی که بخواهیم با رابط کاربری در برنامه های اندروید خود تعامل داشته باشم استفاده می شود. اگر میخواهیم از این استفاده کنیم، ابتدا باید دیسپچری را با استفاده از آن تنظیم کنیم Dispatchers.setMain(dispatcher) .launch(Dispatchers.Main)
- این Dispatcher نیز برای عملیات شبکه و دیسک است .launch(Dispatchers.IO)
- یک توزیع کننده Unconfined در کاتلین کوروتین به یک موضوع خاص محدود نمی شود. launch(Dispatchers.Unconfined)
در قسمت پایین من یک مثالی از Dispatcher ها برای شما اماده کردم .
برای استفاده از کوروتین ها به چه چیز هایی نیازمندیم ؟
- در ابتدا ما باید کتابخانه های کاتلین کوروتین را به برنامه خودمون اضافه کنیم .
- Scope ، دامنه یا جایی که کوروتین در انجا میخواهد اجرا شود .اسکوپ مرز های اجرای یک برنامه کاری را مشخص میکندبا ازبین رفتن یک فعالیت باید تمامی کوروتین های مربوط به آن نیز به صورت خودکار از بین رود.
- ِDispatcher ها برای تصمیمگیری در مورد اولویت اجرای Threadها میباشد .
- Coroutine Builder : وظیفه ساخت و در مواقعی هم راه اندازی کوروتین را بر عهده دارد .
- Job :نشان میدهد که کار ناهمزمان میباشد .
اسکوپ فانکشن های معروف کتابخانه کاتلین کوروتین:
- delay:این تابع کوروتین فعلی را برای مدت مشخصی به حالت تعلیق در می آورد و یک برنامه کاربری را برای مدت مشخصی متوقف میکند.
- yield : این تابع کنترل را به سایر برنامه های که در حال اجرا میباشد میدهد .با این کار ما به کوروتین های دیگر اجازه میدهیم تا در جای خود در حالت بیکار اجرا شوند. و به نوعی عملکرد کوروتین ها را بهبود ببخشیم .
خلاصه مطالب
ما در این پست در مورد کوروتین ها حرف زدیم و فهمیدیم که کاتلین کوروتین چیست ؟ چه تفاوت های با Thread ،AsyncTask و Rxjava دارد .به کمک kotlin coroutine کار های سنگین و پیجیده در main thread انجام نمیشود و همین امر نیز باعث این میشود که Thread اصلی ما مسدود نشود . فهمیدیم که Coroutine builders ها یک روش مناسب و مفید برای ساخت و راه اندازی کوروتین ها میباشد. نکته دیگر این که با کدنویسی همزمان و غیره همزمان نیز آشنا شدیم
موفق باشید
دیدگاهتان را بنویسید