Ali Shobeyri
Ali Shobeyri
خواندن ۴ دقیقه·۵ سال پیش

عملیات Join و Cancel و Yield در Coroutines

قبل از خواندن این مقاله این دو مقاله رو بخونید :

  1. پیاده سازی Coroutines در Android و Kotlin (مقدماتی و ساده)
  2. معماری Coroutines در Android و Kotlin (نگاه جزئی تر)

Join

این دستور این معنی رو می‌ده ، کوروتینی که در حال حاضر در حال اجرا هست رو suspend کن تا job ای که join شده کامل بشه ، به مثال زیر دقت کنید :

در این مثال ما درون یک کوروتین یک job رو اجرا کردیم ، دستور join در اینجا این کار رو می‌کنه : تا وقتی job کامل نشده دستورات بعدی اون کوروتین رو اجرا نکن ، پس خروجی به این شکل می‌شه :

اگه job رو join نکنیم :

وقتی job رو join نمی‌کنیم دستور خط done بلافاصله قبل از اتمام job چاپ میشه ولی اگر join کنیم تا اتمام job وقفه میفته
وقتی job رو join نمی‌کنیم دستور خط done بلافاصله قبل از اتمام job چاپ میشه ولی اگر join کنیم تا اتمام job وقفه میفته

Cancel

زمانی شما به این نیاز دارید که job رو لغو کنید (به هر دلیلی مثلا زیاد طول کشیده یا ...) ، برای این کار از دستور cancel استفاده میشه :

اما کد بالا می‌تونه بهتر باشه ، قبل از بهینه کردنش به این مثال دقت کنید :

به نظر شما خروجی چیه ؟ قبل از دیدن عکس پایین کمی فکر کنید :

می‌بینیم که طبق خروجی job به صورت cancelled در نظر گرفته شده و active هم نیست اما این طور در نظر گرفته شده که completed هم نشده ! اگر قبل از لاگ مربوط به isCompleted یک delay بذارید می‌بینید که به صورت true در میاد ، ما این رو نمی‌خوایم ! ما می‌خوایم وقتی job رو cancel می‌کنیم در قسمت های بعدی اون job به صورت completed در اومده باشه ، پس می‌آییم cancel رو با join ادغام می‌کنیم :

در کد بالا کوروتین تا موقعی که job کامل نشده باشه suspend میشه ، میشه این کد رو به این صورت هم نوشت :

cancelAndJoin : cancel + join
cancelAndJoin : cancel + join
نکته : می‌تونید دستور launch رو به تنهایی درون یک کوروتین اجرا کنید ، یعنی به جای اینکه job رو به صورت‌های بالا اجرا کنید صرفا جلوش launch بنویسید (به جای CoroutineScope(Main).launch )

Yield

کار این تابع به طور خلاصه اینطوره که اگه شما اونو فراخونی کنید میاد اون Thread یا دسته Thread ای رو از کوروتینی که دارید درش عملیلات انجام می‌دید میگیره و به کوروتین‌های دیگه میده ، با مثال این مبحث رو توضیح می‌دیم :

به خاطر اینکه در مثال بالا ما فقط در یک Thread کار انجام می‌دیم (یادآوری اینکه وقتی IO یا Default بگذاریم در چندین Thread کار رو انجام میده ولی Main فقط یک Thread هست) چون job2 در مرحله دوم اجرا شده پس Log هاشم بعد از اتمام Log های job نوشته میشن حالا اونو به این صورت در بیاریم :

اگر این کد رو اجرا کنید در Log هاتون می‌بینید که Log های مربوط به job بعد از job2 اجرا میشن ، حالا اگه yield رو توی job2 صدا کنیم چی میشه ؟ هیچ فرقی با حالت اول ایجاد نمیشه چون در job2 در حالت معمولی بعد از job مقادیر رو برای ما چاپ می‌کرد ، حالا اگه به جای Main از IO استفاده کنید و yield رو هم در job بذارید شانس هایی که برای چاپ کردن job2 دارید از job بیشتر میشه و با اینکه به موازات Log ها رو چاپ می‌کنند اما می‌بینیم که در انتها دسته‌ی زیادی از Log های مربوط به job آخرِ سر چاپ میشن . می‌تونیم با cancel ترکیبش کنیم :


می‌بینیم که Log ها کامل چاپ میشن و بعد تازه کار cancel میشه اما با yield :

بیاییم مثال IO رو هم ببینیم :

و بعد با yield :

دلیل اینکه تعداد بیشتری نسبت به حالت Main چاپ شده اینه که در IO از چندین Thread استفاده میشه ، پس وقتی ما yeild رو صدا بزنیم ممکنه این وسط ها به دلیل متعدد بودن Thread ها فرصتی برای خود Log ها برای چاپ شدن وجود داشته باشه .

اندرویدتوسعه اندرویدcoroutinesکاتلینkotlin
برنامه نویس اندروید - https://www.linkedin.com/in/iryebohs/
شاید از این پست‌ها خوشتان بیاید