Kumpletong Gabay sa Pagpapatakbo ng mga Asynchronous na Gawain nang Kasabay ng mga Coroutine

  • Konsepto at operasyon ng mga coroutine bilang magaan na subprocess upang maiwasan ang pagharang sa pangunahing thread.
  • Mga pangunahing pagkakaiba sa pagitan ng paghawak ng asynchronicity sa mga wikang tulad ng Python at Kotlin.
  • Paggamit ng mga Dispatcher, Scope, at mga constructor tulad ng launch at async upang ma-optimize ang performance at concurrency.
  • Paglipat mula sa tradisyonal na modelo ng callback patungo sa asynchronous sequential programming.

Pagpapatupad ng mga Asynchronous na Gawain Kasabay ng mga Coroutine

Kung nahirapan ka na sa performance ng application, alam mo na ang pinakamalaking sakit ng ulo ay karaniwang ang mga gawaing matagal gawin, tulad ng pagbabasa ng malalaking file o paggawa ng mga request sa isang server. Dito pumapasok ang mga coroutine, isang kamangha-manghang tool na nagbibigay-daan sa atin na mahusay na pamahalaan ang sabay-sabay na operasyon nang hindi nagfi-freeze ang user interface at naiinis ang user.

Sa madaling salita, pinag-uusapan natin ang isang paraan upang sumulat ng asynchronous code na mukhang synchronous. Sa halip na mabalot sa magkakagulong mga function na tumatawag sa isa't isa, hinahayaan tayo ng mga coroutine na ihinto at ipagpatuloy ang pagpapatupad ng isang gawain, na nagpapahintulot sa processor na gumawa ng iba pang mga bagay habang naghihintay tayo ng tugon. Ito ay, sa esensya, isang paraan upang masulit ang mga mapagkukunan ng system nang hindi kinakailangang ginagawang kumplikado ang mga bagay.

Ang mundo ng mga Coroutine sa Python

Ang Python, bilang isang single-threaded na wika dahil sa sikat na Global Interpreter Lock (GIL)Kailangan nito ng mga trick para maiwasan ang pagka-stuck. Para dito, ginagamit nito ang loop ng kaganapanna parang isang konduktor ng orkestra na nagpapasya kung aling gawain ang isasagawa at alin ang iniiwang naghihintay sa isang pila na may prayoridad. Ang aklatan asyncio Ito ang mahalagang bahagi rito, ang pagpapakilala ng syntax async y await.

Kapag tinutukoy natin ang isang function gamit ang async defGumawa tayo ng coroutine. Pero tandaan na ang pagtawag dito ay hindi mahiwagang nagpapagana nito; kailangan natin idagdag ito sa loop ng kaganapan, kadalasan sa pamamagitan ng asyncio.run()Kung gusto nating magpatakbo ng ilang gawain nang sabay-sabay, mayroon tayong mga opsyon tulad ng asyncio.gather() o ang pinakamoderno asyncio.TaskGroup, na nagbibigay-daan sa iyong pamahalaan ang mga grupo ng mga gawain sa isang nakabalangkas na paraan, na kinakansela ang lahat ng mga ito kung ang isa sa mga ito ay nabigo.

Sa loob ng ekosistemang ito, matatagpuan natin ang mga bagay na hinihintayAng mga ito ay pangunahing nahahati sa mga coroutine, mga gawain, at mga futures. Habang ang mga gawain ay ginagamit upang mag-iskedyul ng sabay-sabay na pagpapatupad sa pamamagitan ng create_task(), Ang Ang mga futures ay mga representasyon ng isang posibleng resulta na hindi pa dumarating, na lubhang kapaki-pakinabang kapag nagtatrabaho gamit ang lumang code batay sa mga callback.

Ngayong TV programming Android app
Kaugnay na artikulo:
Kotlin: Ang Mahalagang Wika para sa Android at Cross-Platform App Development

Pag-master ng mga Coroutine sa Kotlin at Android

Sa ecosystem ng Android, ang mga coroutine ang kaligtasan upang maiwasan ang kinatatakutang "impyerno ng tawag pabalik"Ito ay isang sitwasyon kung saan ang code ay walang katapusang nag-i-indent sa kanan dahil ang bawat kahilingan ay nakadepende sa nauna. Iminumungkahi ng Kotlin ang sumusunod: mga tungkulin ng suspensyon, minarkahan ng salitang suspendna maaaring pumigil sa pagpapatupad ng isang coroutine nang hindi hinaharangan ang thread kung saan sila tumatakbo, kaya pinipigilan ang mga ito na mangyari Mga error sa ANR, pag-crash, at kernel panic sa Android.

Para gumana ito, kailangan natin ng CoroutineScopena siyang saklaw na tumutukoy sa siklo ng buhay ng gawain. Mayroon tayong GlobalScope Para sa mga gawaing kailangang manatiling aktibo habang nakabukas ang app, ang lifecycleScope nauugnay sa paningin at viewModelScopeMainam para sa mga operasyon ng datos sa ViewModel. Kung kailangan nating baguhin ang thread nang mabilisan, ginagamit natin withContextna isang suspension function na nagbibigay-daan sa atin pagtalon sa pagitan ng iba't ibang konteksto ng pagpapatupad.

Mga Dispatcher: Saan tumatakbo ang aking code?

Ang dispatcher ang nagpapasya kung saang thread tatakbo ang coroutine. Hindi lahat ng dispatcher ay pare-pareho, at ang pagpili ng tama ay mahalaga upang maiwasan ang pag-crash ng app.

  • Default: Na-optimize para sa mga gawaing nangangailangan ng CPU tulad ng mga kalkulasyon sa matematika o pagproseso ng mga kumplikadong JSON.
  • IO: Ang matalik na kaibigan ng mga kahilingan sa network at pag-access sa database, dahil namamahala ito ng isang thread pool na idinisenyo para sa maghintay para sa mga panlabas na tugon.
  • Pangunahing: Mahigpit na nakalaan para sa pakikipag-ugnayan sa user interface sa Android.
  • Walang kulong: Hindi ito naka-link sa anumang partikular na thread, kaya hindi mahuhulaan ang kilos nito at dapat itong gamitin nang may pag-iingat.

Mga Konstruktor: paglulunsad vs async

Para magsimula ng coroutine, gumagamit tayo ng mga builder. Ang pinakakaraniwan ay... launchna nagti-trigger ng isang gawain at nagbabalik ng isang Bagay sa trabahoSa pamamagitan ng Trabahong ito, magagawa natin ang isang join() hintayin itong matapos o cancel() upang ihinto ang operasyon. Sa kabilang banda, mayroon tayo asyncna siyang hiyas sa korona kapag kailangan natin ng resulta. async nagbabalik ng isang Ipinagpalibanat sa pamamagitan ng pamamaraan await() mababawi natin ang pangwakas na halaga.

Ang tunay na pagkakaiba ay habang launch Ito ay para sa mga gawaing "barilin at kalimutan". async Binibigyang-daan magpatakbo ng maraming gawain nang sabay-sabay at pagkatapos ay i-synchronize ang kanilang mga resulta, na lubhang binabawasan ang kabuuang oras ng pagpapatupad. Halimbawa, kung mayroon tayong dalawang kahilingan na tumatagal ng 2 segundo bawat isa, ang pagpapatupad ng mga ito nang sunud-sunod ay aabutin ng 4 na segundo, ngunit sa async Dalawa lang ang kukunin nila sa kabuuan.

Mula sa mga Callback hanggang sa Sequential Programming

Ayon sa kaugalian, gumagamit kami ng mga callback upang pangasiwaan ang asynchronicity: nagpapasa kami ng isang function bilang isang parameter na isinasagawa pagkatapos makumpleto ang gawain. Bagama't gumagana ito, ginagawa nitong... mahirap basahin at panatilihinAng paglipat sa mga coroutine ay kinabibilangan ng pagbabago ng mga pamamaraang iyon tungo sa mga suspension function.

Sa Android, madalas itong nakakamit gamit ang suspendCancellableCoroutine o suspendCoroutineAng mga blokeng ito ay nagsisilbing tulay. Nagbibigay ang mga ito sa atin ng isang bagay. pagpapatuloyDahil dito, masasabi natin sa coroutine: "maghintay dito hanggang sa tumugon ang external library callback, at pagkatapos ay ipagpatuloy ang pagpapatupad gamit ang value na ito." Kaya, maaaring tawagin ng ViewModel ang isang repository function nang linear, na binabalot ito sa isang block. try-catch para pamahalaan ang mga error sa network nang natural.

Mga Asynchronous at Reactive na Daloy ng Data gamit ang Kotlin Flow
Kaugnay na artikulo:
Kumpletong Gabay sa Mahahalagang Konsepto ng Kotlin para sa Pag-develop ng Android

Ang mga Coroutine ay napakagaan kumpara sa mga tradisyonal na thread. Maaari nating ilunsad ang libu-libo sa mga ito nang hindi napupuno ang memorya, dahil hindi sila lumilikha ng hiwalay na thread ng operating system para sa bawat instance, ngunit sa halip gamitin muli ang mga umiiral na thread sa pamamagitan ng suspensyon. Pinapayagan nito ang mga kumplikadong aplikasyon na mapanatili ang kumpletong pagkalikido, na nagdedelegate ng mabibigat na load sa I/O dispatcher at bumabalik sa Main thread para lamang i-update ang screen. Ibahagi ang artikulong ito upang mas maraming user ang makaalam ng impormasyon


Idagdag bilang ginustong mapagkukunan