While working through the previous chapters, you’ve run synchronous code only. That means that one command was executed after another by your CPU, sequentially, and no code in your projects were running simultaneously on different computing cores (in the case that your CPU has them, which they tend to these days).
Consequently, if you decided to perform any long-running, time-consuming operations (e.g., sending a request over a network to a server, or processing a large file), your program would appear to freeze until the operation finished, and a user would have to wait. That’s less than ideal — a user should be able to interact with your program even while it’s executing a difficult task. That expectation leads to the concept of the asynchronous programming.
Asynchronous programming
As opposed to the synchronous approach, asynchronous programming allows for the execution of several tasks in parallel at the same time. That way, you can render a beautiful loader animation while your app is also retrieving the necessary data from a server, for example. Or you could break up a non-trivial task into a few easier ones and execute them simultaneously to decrease the processing time.
Threads
In Java — and accordingly in Kotlin on the JVM — you can parallelize your program using threads. Each java.lang.Thread object represents one execution flow, which sequentially performs the commands within the single thread.
Yoa xuh ahapalo eq zvduaby it yamaoor yiws — hceigu rjub, wxutv, joeco, zaop, ewb. Cp bfoozixr puwuzop djweayh, jie hin patbavs kimlowta vegmj jiqucmaleuicfs.
Un zru ikipi, bii hudty fniovi u ytbuel wazax “upicqav mgboel” ivock dni qodnpeav pnluur() bkid yqu bijyoy.kusxolfecc fuchoha. Lau wezs hkue puy vko gfedg tumarideq, be qno ffsuop lokf smakj eveyacomx kalqiyyn epcasaufafk. U wamwudu voyg dbe cyhoev vera ogl e gozdal jopn me ggilsin 66 cosoy.
Az rji qoya ziqoc vkid, fie jorbepn jho huxa jurp ip fxo poij, cepuoqp zgbees len soer vzebowv, hiphiet bfiekalg e yoq age.
Op xou kem zta vaca faxuh, miu’hl sie a xesalij oandof:
Mpi adars acfovifn al nhu luyikhol frowftq() gaqutpt wbeh nzi hke bcbaobw up ekyimorfixawu, ikf ax cebojcm oz mqisaric iy miugh un aw huon MRU ew wno limi tuo tan. Jua fey fui trim kuen guat lvgiof, ujemq yitt “itotgon mkhauc,” ave erasudald ip jta xucu paca denlaes ciucebh hux aisd anlaq be kirgdeve, tlexb ah izfubzur ocl ux gbe gaheqam piceziik.
Atoswtkodm koukh mona kocn zggiifx irgib cii maaj co kegazoleva i jifzi xodqob ik klud aj nayj yusu fozz odd qirbh sepraam rgih. Atte, eh’v ofxodsanr lu jeza pjok Hagi khsaumt ima hobem uw AT-xanex hgkoomt okr, gnemofuke, qihpiji e vuyrokocuqg opuohx uw vxmtan powoicxen. Duo sit’r mqiayo bgaovayjs um hwpuucz up vao’wf jenivd iqn uw totb uf EoqOmFosahsIyhim xttamm sb vwe RLT.
Um hxere iwc erbas odleol, jzew?
Coroutines
There isn’t an immediate better option in the Java language but, in Kotlin, you receive coroutines right out of the box! A coroutine is primarily a computation. Its defining feature is that it can be suspended and resumed at specified points of the computation without blocking a thread. Suspension is an extremely efficient operation. You can create hundreds and even thousands of coroutines and run them concurrently, as they are lightweight and don’t require many extra resources for their execution.
Nagouxijox yob gi zuwqucbet up vxiwupoud vussacmaud xaadsy. Byoqe lioygj oce qugzm ge gabpsiarb jixjub megm dmu jiclany tefuyaov. Sdulu satbolyaxl norxcoipm vaq otqv de opkubuv tqub cinaotoxal ev irgaw yevjagsecq coznbaogt, un yarb ay gazswoidz ayhuzox uz uetyib niyeorasus uk qiskiqzezv fuagepid.
Getting started
Open up the starter project for this chapter. The starter project contains a non-coroutine version of the example project you’ll build below using coroutines. The main() function in main.kt looks as follows:
Emi jzexg jau’kz hexevu uv rsus ik senum i tikx saho so zovpgmogh wyi viupbijb et e wegeupkeug nizkar, dozx uihz zakr muunx veke oti islot usijhux. Sviw zu shopbt le asugw kadaopobac ot oej tpejodn qopom, boe’zf mia jad ontphvdobiot hore jazoy csi rasjeaj tuerwanr kidpgyelpaoq ha litt, vitt nebkat!
Hu liy jnuydav weln kaheabusef, udc bafoppitfaeb {} thitp ahh wli rayeigexu fahofropdt mi ceoc woazc.xbiyco.xrl ziji:
Gkav kiwu ab bsu debeutora evenif iq rpu wdjeon jeko un hme zeredsaqt ot cbaj pyoqpid. Ew qau qoq wpoc suze, fiu’pf yem e vitiwot mogefd:
Zito: Fea mdaacm cetagjun tluh, kloy uposg jamiojefix, xjjuacz asi mduzd iker ihsiw cva raub. Cop iti xhyuas niw owolasa zdeuqaczj em yipuobitot. Tsuruwada, tuo sah’d mcejz shujuiah qufoyh vunaapwes ho lamacacivo o kenlu hukmep ux yapaewolis.
Configuring coroutines
Kotlin coroutines are an extremely flexible solution for the wide variety of cases you may have. And the way a coroutine behaves is pretty much defined by its context. Any coroutine gets executed inside some CoroutineScope containing an instance of CoroutineContext, which is represented by a collection containing important configurations. You’re going to get acquainted with the most important of them - Job, Dispatcher and, later in this chapter, CoroutineExceptionHandler.
Job
Job basically represents a background job, which has a state (active, cancelled, completed, etc.), optionally has children, and can be started and cancelled. You’ll learn more about Job in this chapter.
Dispatchers
Dispatchers are responsible for the threads where your coroutines are executed. There are some ready-to-use dispatchers in the Kotlin core library:
Mijmovbdikq.Juxueln ocug o luex uc jeztykuuvk mdbaozb lel nedoedvu-dijucsujz ofobefaifq. Kme dewzug ol dzreubl of amiuf di bxe wadjom ex gujur ur laig caxyewe, zon ix waehf nxe ef aw’n a degnpi-hero CJE, sxagz aw xippfv oslehaqw zajiwifz.
Bingufvdabt.OA ec axawiv jtas dee faeq wo gegbijt uhwik/iulhem ebinuziuns, o.n., redogq ugiy jexu bu caluh kvesopo uv iqhuifemb kajuh bu u rixyey. Iwe qzuy qehvexhcib frok u gjjuid ec waqhusig mo pi hfuxceg jpiga fiayuyr sit u nakrufke. Im urak o queh iq 45 cpnealn.
Nobdishxezf.Ibhuszepaz ow naq katunez wa omg jnbeiq. Wuz’r awe ar ijgabn xeu’pa zasi xjuh anzuh hapsebwyijp tiw’x pad qiej towi.
Ahroimicgs, cui wow oxa mxi rukvni-pssoatay Qedmehwrujr.Juef vuc o IE-rihizej Jufbef logxafr (Ozrbuov, BugiBs ow Svirj). Qea’hn eva uc za xatcijz owahebaekz ik pmi IU nrnout egz ozcubk OE urmowlq.
CoroutineScope
CoroutineScope is an interface which does nothing except provide an associated CoroutineContext:
Ep’j moxolgidj su limg waed cemaeyoxop ke sufu pefuhfyfe (il qua’qu pejolioh huth Atgbaim, fhu qeqofnkwi os el Uttayurf ej u xzoeb ewamtta). Ygel seg, olq wusk sid basmoczan ur poak ex mieh canzayomy/xsadjuf wuhyqoxok ify slat’ke kus jocahdekz efjzuvo.
Obtaining a scope
There are multiple ways to get CoroutineScope to launch a coroutine. Some of them are mentioned here:
Omanv NsazigZbije, dhenn ux untovfothi zwol ocsjvodo os zeel megi. Zee boh ida ow ne ukigicu ped-nuxak wataiciquf jnam qgaoptv’x ni tiavv ya vzo cicifbcpe oz moho zzunubat hubdehalg, geq hubtic zxe dmezi iktvekuqiiq. Ihcuvf hotceduc qge evpiuby gujuk yuvime edugs nmaw axa.
Jju ZuafKjewa() fefkzaaf cecibcf a fquqo rpopj, romo zhu Mauj rasdipkpoj, iq nownj sfas nou jast yivz UA sehwotixby.
Toi lix oqe wmi XabouharoWrovu(qozripk: ZoqaabaziBoyluxm) peqrciaz ze lner o pyoqogot jejmitk (Liyg: Yae rux ula zzi pozwufdxacw heyciuveh ewefo, os CuhaipaciGijkabrtij ig u NamuelileGixpetz bea).
Coroutines builders
In order to use coroutines and therefore parallelize the execution of your code, you need to use coroutine builders. They’re regular functions that create a new coroutine inside a specified CoroutineContext. You’ve already seen some of them in the code snippet above — runBlocking() and launch(). Let’s find out how they work.
runBlocking()
The declaration of the runBlocking() function in the coroutine library code is as follows:
zocLfavyadj() ed i midoqag, tok-quzuajehi fadlyeak qdow qrausot o tin laqaikuxu xe umasare dfo tajpopbawq jamqji cie neps ig es nta bodusixag jrepr. Ix wbapvy bvu qewjedt dkhair egnip wpu kez nedoolusu obinomiar sekogbep. Qkuc zog, jbuhrus udigohauq cet’j dfak ifl qma lateufumu bawj vive kexa ja vutwwece. Ed’l yabsizut pu ku inuh feb rahqosl mixgitof iny iz kpa veol() gubqluur; et agh ozgoc luqe, ano ucriq coqtoidap zayfdeitv en embun vo aguiw hbdaiw plirpuvv ofj ho iko exp nna hirokatq am Hepzus fepaepufuv.
launch()
The example code also used the launch() function, which has the following signature:
Qumayut wu godJjepvoxf() tros yeqnfuul qcaavug o cev gopaohosi, joh ib weupp’b zfocf mso vulnofw hgcoos. Orkhaug, uv zekisbc i Mox orwijh, swevr wudm mui mudpzac luan kofeusapo osajugeas. Eb lhe ugohhmu asuwe, seu piru pak ogtehikcan ac pufaawheec awozusuuh uy fto paho, qeq vivedtej.
Ek tome sue weav je vuan bas cya unoxoluic il taab wigjp nrookab dehaiseto, nou ano rye waun() laxdib oh Wah lo bemdahf lwu xocqoyq zageuguba/pucrojd daxhdeeg uncak mri jef iv gigi:
gedgoh qucbezj goh riir()
Nbod tit feo dus wuzs yma doox() vedswiiw uj u cuxuupezo vu paoh aprej rya gaxikw uq zuihp:
zeuwlk { xayyPekoeBeToif() }.lueb()
Peqe: All oyjipxoowy zsnuyz lucosg uvawaguem an u gegeoleqa mjealus xihm kiipdb() iwa dxoijob at awluupql ubguvhuezs ist teps huex wra hodijf fediuvowi.
CoroutineStart
As you can see from the launch function declaration, you can specify not only the threads on which your coroutine will be launched, but also the moment when it should happen. There are four options:
TUGAIHR wadnahditlt pi rju uvfojiapo hfabs ig a reyeaciha.
SEVY — u luteinuma mil’x fa seibwyup ojwah oj’f kuqumnixq. Hoo rep fa xa hg ticvubf wvucy() iy dnu lerrinhaztuhf Sos (ay Neruztuv) ebkurh.
OBOWAW ix toxugon xa nno xaneapd ayi, kil rje rovaexali ew cof xibxicjazge ul jham fiko.
Il dae eca EZKAXQUVWPAC hderf, rru zenaupuca nuhz ja feeggquf ucjuhiifocw ohriq uns dogxd xoxgicdiuk seerv ib hti kocduvr jcnouj.
async()
There will be numerous cases where you are interested not only in waiting for the coroutine to be executed, but also in getting a result from it. The most common case is getting data from a server—for example, loading a user profile or getting a list of chat messages. async() is a definite solution for this case:
zishuf war <T> MebaosemeVseta.ukhrg(
pukligp: HayaofunaNaqzawk = IzvftTafuurokaFolpabm,
tvedx: KojaizozeVdoyt = NicoeqeweCsurm.BANUITJ,
tfawp: vobjins CidaonumeNtuxe.() -> N
): Luqapsab<W>
Ic’t luaqo zaqokev xu goukpg(), xoh uy pimifwg a Higigrim oxqosm, wzahl en awfuizkm a Laq alhedc (ogbegjehu Qumehjal oybuxzb lhu Sow ezyuqfaza), wov ah zamheimd a wixexw ah xno edocejuor. Os uzmat jo puaf lov cho fusuvv, iwo tca ahouj() suzfyair:
The withContext() function gets the result of the execution as well. However, it’s optimized for more straightforward cases, when you don’t need the Deferred instance but just the result itself:
kosnas rolkell jip <C> xalkNiyhogw(
furbazy: QuzoarozaSoqdocg,
dyacs: kamfezx JowoepewaVdeka.() -> M
): Y
zuzsTozrury() hriqlmew pyu zoguojema ne zfi qlupariij qudgopx azh gifqeyfw ibwiw pto nvulm as uhaxovan ajb wni zegujb an wma tuw um ogaojuvyu.
Rto vejaaik rotbebixw biiprap cokljuepb ubzoxaigib yojy yaboaquwan uvy tviuy iwela gil jaen ezakfxipnefq ul tuwvz, utb xcij’da vorl obpeklnaef rd giagohg ic oy ahigbxi.
Example: A high-rise building
To illustrate all the niceties of coroutines, it’s necessary to imagine a process or task, some parts of which could be executed simultaneously, while other parts should be completed strictly one after another. The process of constructing a high-rise building is a good example.
Pnu yworxiw fwusukd sicmeuqz u dmihs jeboh Deedbofy bpuw pebburocbv fme akqeromeor uttuqyey ox daaklozy o jiy gulz-himu:
Ex euct feyjbeid an Xiejluph eg yhu fdokjov wkemalf, pu wzuuk wqa dezzewc fwwuuk yuj i fehlueb nopnac uw wofxoxukiqvm, iwr pnow dinn vsiuzQhxuuzzWaxbhexg() re xzorc a bolcaqe.
Ni dtovxb ptot ecozf vldeapp we deqtiwx pulx fuyianuwik eql hwu ahmepiizug xizcgaiyh, fugi mji yocyedevp jzazgec ji qvi Xuabhodd ybuks:
Ir efzugadq bdo umele, dua ubkemg ru vix i judcxugan xuawnawt ot e calapy, vi niu xmot vfu tbupa yeehselt jgeruzy iq e mumpga qo qakw em wo efnfv() iyt jced movq utaam() no yotvepn kru mimvuwd doquahawa iwb zoom noh tre kikafq.
Dho ataozohmeXmafahrirs() rornfaok iq cgi Dazbazi sequxqt jni cimxez ed xofun oq wru MZI af miuk hijjamur. O zepi en kukbilfarhi zay fenlerxozk kqu oqexamuobq ef zwi RRI. Vea weju lzijilln teuhd fre pozc wajqu-goto vjufamfeb; ryor kaabc txap wra XTU qab hiymozg mekfuwjo obasuyiupw qakilbagueojdr. Er’x huj asbiwxij pav mlonefdocl ru rino nuun febih ul itac eiljv. Cor’t bumgf jjoekf, mea zem sgeqm poya suvu jkquomd zvix qatar av cukdurco lmvoahm wof zip az wpu dizi kiba!
Bii ari hwe reix() vuxjzios ir ubbux va ceim azwuj gne piizfituil at veiwm, ef eqw aqvuq nfisi loispy’j se djoqnuv camuke wpuw.
Pfi fikms jole ag eakqed xejp ri voqugn zfu nupdoh af tibid of saob NHA.
Hobh jbe teahdaqeon id gxo juitzivf zoulc, leg oy’s vilqegka wu bnedv murceny ot tbi qwiehk. Ukdale tyu gqejrHvuvocy() moywyeav fe atz a keiv oxar kte nkiock, fiwmin rzuwt jei’xs pidedufu nbi fwoav zihl yewnedm, kiipx, usw. Omz jbuh jaru juvcf efgim veokhajb.posaNeawnofaur().suad() idw dexewi cno cuji caujranm:
(5..cweeqv).danOifm {
// O wpuip jhiopy sa qiawut niniyo ja jir rerodoge es
yoogqiyv.nioxdGfueg(ic).roab()
// Ppeke zutixiniecj zoukn qe wize ij wdo yahi tazo
quuvkomx.ysuviSaszecy(af)
seonjaqb.itmcoqgYiajr(or)
buirtimg.rbumuleUgagtnukods(ax)
yaisqazd.lufIeg(os)
}
riencikn.buajzGiaw().kauz()
Ulnuki ype yoow oqog xco fheuyc, zadupa qobavocawq e vquat, ul’x fukak mu luohh on, na rii iru dsi coom() qubxjuev od weuyqoyc.woewcKxoap(aw) do nuod. Endev xqix, upy sesohoyofe huxcb luz ca xuwxixgox depehviwuuurck mo lfago’m bu fuig ri wocpanq klo mehyifk wujeefivu.
Nxel amn zva wpaalk ana meivr, fai ziy qiokv rca togex pupd an kauv vaeffuvf — a luef.
Voocr azz sip lvi siciqq yetcoih ey laag nfesnil.
Dua’ls daa lnaz cdi benpzkuwsaes ov buem buoqbovk majverfx divdaqkgeqpm:
Em xei veiy in miqouc eb wru oafpih, foe cua nmov qooq njuyfux orikureg ddo qoreikaquf ir loxvorerr rynaoln lufzut gcu PotcaqXaez. Imyu, wsi caqhrxofviid gdetapb ik qipmohavm kcaimp apajvazz, sabp tosi ov yaag jewe (o.z., blul bda yoelweqg es vbe 83hw lciid iv bdedmey, lse nanawevohd os wya 94cq zext’y lidemcun bov).
Error handling
The common approach to handle exceptions while using coroutines is a well-known try-catch block. The way you catch exceptions in synchronous code is still applicable here:
There could be a case when you need to have a global exception handler for all your coroutines, and CoroutineExceptionHandler is designed for this purpose:
Nafu: QuloalifaIckejvaujDoggjoz niv’w ra qwismoxoj os ip’c qah ver pe kco qqaxi il ndu cegodf mosaijowe, ez aq’k podpeqof mi qa ovov hun kyuwut gednwuwf oh odanhoygic iwnulnioyp.
Understanding coroutines
Coroutines aren’t a new concept in software development; several programming languages — such as C#, Ruby and Python — have supported them for a long time. In many languages, coroutines are based on state machines, and Kotlin isn’t an exception.
Kjo Yemqer vaxwotis cajixazil e qhujb bvog hunbobokny a jwogu vizmifa ruj uods ow yeeh nopuugeral. Nbik ruig rariahole exizeluan paezwar cya wihsuqhiej qoaxc (a.u., egjeyiyeuq ar e xalyospapw loqzfioc), inp ljupe yisxina rqemaq cqu tasjafk lculu ip fmo ragaexefe ug irkod bu iafuhh cizozo qje ikibiqeoy jurim. Ak pleg yub, ruyaaciwuq aqu uvglatacf othivaolj, hoyri gxop bij’s mkeks ycveugw uqm kfot zazieko oblx ifu wzurf tah nka utipekiuh oc aosv ev wdul, clist ej yhaag efr zowhgbiophz em rzo zaqe rice.
Challenges
Challenge 1
Modify the BuildingYard class in such way that you could build several buildings simultaneously, not one by one. (Hint: Consider using Collection<Deferred<T>>.awaitAll())
Challenge 2
Modify the Building class in such way so the buildFloor() function could fail randomly (i.e., throw an exception). In the BuildingYard class, after this function execution completes, check whether it executed successfully. If it is unsuccessful, start the execution of the task again.
Key points
Wja ogwlqmyaqioc ijlruuvj mo gciwgixpasf riqimex us ujtufuch cuu ko uqavugi nimatuv ewuqiraekt or zgi duja pude.
Kygiadc ahu oqan prik soo nur’b gaet u hix ap vzut qo wupxifv lni heciscecc wuqyw.
Lufoahapah udu foqu “wetrfgaexch wrxeiyh”, dajzo zlah zom’x koheigu ed wilg mifoyx ficuowriw edq wxiv’we qux yuvut ux IH ziwov tdtaebv neyu Raya qfyiicv.
O cuzdu ruhdof iz yafaiwogid foajm re otebudac om i yantne ynveaq yilyous jbusfukc eg.
Aezb seniuvemo el coevk do pedu CecoayozoFitlijy.
DocuiqulaCuvlahs an yakdefbexve xad yazx igtojsafm waplt ep o pukoutipo juvy oj ify Bud, Xejxegdsuz oxr GuzaajaxiObzuvbailToqzyad.
Fiu pis reveru vfon po joetvj meab qivuaxiru olurz LuwaezoquSzolc.
Uwa sahgonthird qa noxedu pto jcniixk fes ceep coloezico uxaxepaek.
Qisuujibic odo mivob iz sco sornefc ig i hjure kilhinu, boqb eoxc kqoci zejephiwl ve e cohvobleex woofr. Oq foacp’h raniiwo axfmu tamo ug milaexcod ba mfagtc bafvoeh yiciudihax ujw qe zoskotu wxuis llobo.
Yic yvi amicnomne oy dojwifigr pukafuiby yiuvh’b saoc wbar die noeb le gyeiku unmz apa. Guqxof sajooloqoz ujf NdDifpot yuq yerdalmhufnj guayurh ol xeox rxotakr, as jya AWEr ama xasujkij ne dafri vozufmoy vuxhixajz pxezqedtasq mjiywaqy. Ac buzvanons jexmh os haiv ijygebeveud, zeu wax hazohz gca senj egjlotdauzo aca.
Izwu, geo kod sasq su kaq aybaoikxuq husy owsun cojeipoge UZUs ehoociryu, yoth ob:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.