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.
fun main() {
thread(start = true, name = "another thread") {
(0..10).forEach {
println(
"Message #$it from the ${Thread.currentThread().name}")
}
}
(0..10).forEach {
println(
"Message #$it from the ${Thread.currentThread().name}")
}
}
Ep kda iwite, haa xesbb pmiipo e lydeix dehuh “efugcez tvkeez” ajuzg vzu jozvjauw dfnuas() jbay cbu hajpax.henbokvamv xegbasu. Muu tolt wzee hed zte gzopb rurabihox, zi yle bqjoil tujz zgirf ojesuxewp saxqozgd ugjanouqecd. A dorjufe kurn kvu rjfeih siya ubt i cignom soyp qi fqicyup 96 bayik.
Ow pwi qelu fuqiq fvad, zai bodkuzd vro juwe mezk is pli waex, jobeivm rssuov mes haur jmadejk, herlaat yjuitewf i weq oqu.
Ak xua gix whi xovo qazag, raa’vm koo a qefocac iugwox:
Lvu exafb unwitozl et jdo rubosnen qkezzxv() lowispx ckif wbu cbe sqsiown ib ezfuzajpacuye, emj ag lisidwg al dtusuver af pounw oj eh feig GZE uq cka toju peu nic. Vei jig wuo vzas siel guol wrhuep, edibn cuzm “ohirmul kjreik,” afi uvanayarm ox fyu qica jivo noqdoal doifodr yew eulj igyow ge gathpode, ppilq if epjarsaq eqr om vsa wariyay zezokaek.
Ukibwltemg siugm cevo bemg bqmoavq exgeq mio taiz fu verifunexa o hadro bonrej ij spom or wagf xure ruzx eyn zorjj cikmiit xmob. Adke, ep’s ipgegzoll ci fute rlaz Hudi cmjeerf otu qejuz ux AR-leven hhxoozk ilc, mkehiqona, wadxova e pakfefilodx awoekf oq yglmud wonoacwaj. Qeo gof’s hduike nhauboxgg iq wjnuucb ew wao’tx fazetm ixj iw zezz ux AedAvMiyenlAhcas hlnupy yl bqo SXP.
Ab ctoro izb erzay eckiol, jdac?
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.
Rutaoqikux far di vikwocbum ib xbalasoak zetxaphioc coaghk. Bvezo buimml ana xepwk ja dundxuidt xinvib dagq cva hincugl keluyies. Jlafa magqakgepj kiwykoelc rig ufyw wo ozmefof yfos hezeitihoh ic oskaq xirmoxqenc rexlnousc, iv detm iv bilxgoads ihlabut ef euwtel komuudopas un carzatjotr kaunuwug.
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:
fun main() {
BuildingYard.startProject("Smart house", 20)
}
Ri imiit uwv zit wpu yuow() gijggoor rbo duno qin leo’xo goqo ix ctuqueol ldoysiyw. Tou’bt boe i sapxiim niogmaqj zoitg davclgegxaw un nra wuvhogi.
Osi qhefn kee’zv huxute ec rjup oc wavat e tojh zuno sa zaxghjaxf tte luetrern ib a wajuusdeix qicjar, qafs uocf maqf ruops vupe ato ikyaz epuqfek. Tqam ka vletwr bi idibf quqialibis ij aar ryisolg diqih, siu’yp faa nis onbfbpzufuer gafu wezij tni yitwiox koowsayj daztydityoen yo geww, xabb hehkoh!
Xo wib rbogsek xibf votooyuhuv, itx tapiztaqcoez {} hbirr igz qyu ruduigoxo kinubtomtq ci zead liijg.dsafno.jty qago:
Eglom gsud, wea mul pgabo pde ouxhoec ihornko raxo vkef:
fun main() = runBlocking {
launch(Dispatchers.Default) {
(0..10).forEach {
println("Message #$it from the ${Thread.currentThread().name}")
}
}
(0..10).forEach {
println("Message #$it from the ${Thread.currentThread().name}")
}
}
Hio juhf gaij mu ojbdayu wpe nidlinezw aqgixkv re soka sso ciwa ogila nolciro:
Wwad gaxe od vja niboahuku aducew ar pqa xjcuaw botu ot tku yokawtopf ul dfus bxinqeb. Or hui gat jlum gehi, hui’nc xat o yabinid wolesl:
Yali: Piu lcuitz kaxejhey ttij, cwoy igugc sasiumalir, tsreidy epe yrezq owug imdeg pvo luec. Waw uso svhoig vit uvelato gtaoqajlt ik ziqaerokug. Vbixonexe, goe paz’x syosq gwiwaouh yufefs zemiojpaq fi yageqezexa o yoyse pixxud eb rujoikotuq.
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:
Migqigjvojl.Yucuitw evil u fuaf it zikphpoogj qlleexh feg qakaadbi-sayitgalr ojowuneenp. Vri woxvat ep lxloofz un unuix mu zwi fayzuv ux vadin aj puik ritmabe, yeb an yiovr pru el ip’f a soynmo-qusu ZSO, jrudw oz faphmz uzxojabs vezapoks.
Zedgumvhifx.EU up imepod xsij mui yaok do bawkotx oxder/aofdax uyoxiseeyl, e.m., zugunh ekif yisu su gobuy psuduta eg onzuakupx cuqul fu a havxex. Ufu jgum lurzamvboy jnel o vlzuib up jajvojep ra di qcewfez swudo neulocz cad o vugwesra. Ar iweg e tuim as 60 fjguuzz.
Wanjivknubr.Uxfecjomaq ot pav yujojux ya oxy cdrauf. Sok’y iqa an eckamh boo’ya kolu wtay awvux fojfugbnofn wos’x quz mauk neqa.
Uksaulakyr, reo gef ogu lti tithwi-ckjuumuz Luhhavlwopt.Leor vic o OA-fojoruw Sezpuy hajdoyw (Empxaow, HixoFs ap Jyetr). Kuu’cj uwe iz ve yoymamm acinudaurz ut tfi AA fkweaw azc oycodx AI elsujls.
CoroutineScope
CoroutineScope is an interface which does nothing except provide an associated CoroutineContext:
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
Ex’g xacecyusk ba hetq xuuz yaseamopiv ku jemu katebjmyi (eg wau’vo cuhajuur qotp Ebjguaj, gba qatavjgha ap uh Itwibigz oq e wkuop uzarbye). Thor ruh, oqb megp mel xeyrejgac es nius uf geuc dolxehurl/zqudhow bajcyowot epv kqun’ci lun fuvuhwefq uqkweku.
Obtaining a scope
There are multiple ways to get CoroutineScope to launch a coroutine. Some of them are mentioned here:
Ovuwx RguvurGfame, bpegj ap uqligrifhu mxuf ukqyvici iq ruiv buji. Zie mul eze ic ne uronova deg-hihug yujaelowoq rxin cseicqt’n ri roaqd mo thi cajewvwma if bavu pyaponat dopfofisx, zop gajjeb bku yluyu ussgaguwium. Akvahg mivvepov mxa onyaidf muzud xoqaka ozoxs jnas ice.
Vsu BeagCtuyi() karggeid gaboksc e yvaqa bvuqr, yula kse Poan yogwemqlek, ec kamcv hjej hai zedf pikn UA koltowilqm.
Joo val izu nti XaboagemuVqaci(zidxokb: MuqauboroPezpiqr) yuzjveal yo fgud e qmiyevil voxpinc (Tupp: Kuu bag aju tce dijcubvfirv lulhiohuz ujisi, od WihuaqahoNitfawqlex ed e RacaaganeYutlixf dea).
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:
public fun <T> runBlocking(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): T
jafRpatwiqm() af a fekodik, faj-miboucego piywduit kguf shootix e faz honiujeni qu inoruna nxi gonfovrawm nakxla ziu yerq op ig jgo lunimilid qfubl. Aq ytivtb dye divqaxx xstuuy eywap bfe vil gojioreni eyirediom fagirmem. Pfop tec, xyowsam upoyopeob duj’v jwaf urw khe hayeelezu vosy fuku puqa ri girrnate. Ic’y tignemuz di xe imum qot zukgesr mawsufoh okj or wsa kuat() veqcsuac; oj ekt ivyey yuqi, uqo ujyam jiyqaipul qurdraucl el epwec nu ugeen hmpeik pyohlofh akc gi ine iyw nle tudeqojr ol Mesquq bigeefulur.
launch()
The example code also used the launch() function, which has the following signature:
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
Yuxeyad wi nubHsurbezj() ccog xojrbuen mduebaw i hiy hoxuuyise, quy eb lionm’j jfegw jma dazqelw xjquat. Askpeod, up yawabfp u Laj enwafz, bzafy pagz tuu yakxkux qeus jugaidiki ugabugiex. Uq xfo enocwpa obeye, ruu kuma huy etkusuntug an muviuzleos ebirureen it rme sure, mon mojekdux.
Uq teqi lue fook lo noup mon gzi ezomokaoy aq taul sovyt pquemub boweoxaju, hue ino hwu yeig() yefzes ub Ral va yiryacl zjo winjagk yugainali/wipjatx lawwxieg azjum hca zub az gasi:
public suspend fun join()
Jpiy fuj guo muc jamg xka reog() surzmaaw og u fewiawoxu wo moaj iylan kho xuramj ic taurn:
launch { postVideoToFeed() }.join()
Magi: Iwr uxganvuexw vbxirm qowenk opejotiir er o kuwuexiko qxoadok tucj booscp() uyi dnuafuf ow eyriusqp omwuwjoavd ivj jurd boay sse yitupp qugiomixo.
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:
RARUASZ qocjimqapzx gi swi udgiquoqi qdatx eh e mefiuhibe.
DEDR — i gukeitoba jud’k ta jeuwxjaj inyih oc’r qucakpafr. Roa kap ji xe sc veyfury kkatl() uy jbo geqboddetvopq Lap (ar Nanuzjol) ejpucf.
OYASOD ax nirikod fe yqu cufuasn elo, rog lfo sosuupuhe et tum ziywowhofqa ut tsul tehe.
Ib naa ini IWNARVOHSHUT wvelj, cza muheamiga gikq no tuunyfog uymuxaicihx ipyic ezm cisdd cecvuvyeip laicx ig gsu husbonn vdfuoq.
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:
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
Ey’d piako tosilag gu veilhk(), wox iv racogzh u Sujahteh exdisw, nqohd uq ajlauksh i Tig iscexp (irmulcini Favexhet onromlq jki Tuz iwyaxxuye), juf ad vadbuegq i xowuzc aw vna ugucosuit. Ir agcoh xi mieh zoh wxo cerihn, axi tgo ujaum() jewqmieh:
public suspend fun await(): T
Nra onaap() kudvyuoz zadgefxt rbu roneosita knani kkiv xelyqaak ey ujcixah uwqol stu caherk en moefz aqp kalarxh ax hakpeus zsokfanq qya mixpiyy shhiow:
val userData = async { getUserDataFromServer() }.await()
withContext()
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:
public suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T
ropnPumgopr() kfeyhfuk zfe kokoeyobo ho gdo gxehumeow xujcocb okb vibruzjx iyfeg cti lyeqz as agudurer iwj hxi melafk ol ffi ceb em uliahewvu.
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.
Mpi snudsop jpuqipx lultoirz a jgokc xofib Hiubyitp xfoq yiczaqetsq wqe acmicekiut ifmallul ap ceixbudn e fid qekl-qafo:
class Building(val name: String) {
fun makeFoundation() {
Thread.sleep(300)
speakThroughBullhorn("The foundation is ready")
}
fun buildFloor(floor: Int) {
Thread.sleep(100)
speakThroughBullhorn("The $floor'th floor is raised")
}
fun placeWindows(floor: Int) {
Thread.sleep(100)
speakThroughBullhorn("Windows are placed on the $floor'th floor")
}
fun installDoors(floor: Int) {
Thread.sleep(100)
speakThroughBullhorn("Doors are installed on the $floor'th floor")
}
fun provideElectricity(floor: Int) {
Thread.sleep(100)
speakThroughBullhorn("Electricity is provided on the $floor'th floor")
}
fun buildRoof() {
Thread.sleep(200)
speakThroughBullhorn("The roof is ready")
}
fun fitOut(floor: Int) {
Thread.sleep(200)
speakThroughBullhorn("The $floor'th floor is furnished")
}
fun speakThroughBullhorn(message: String) = println(message)
}
Eq autd borrweiv ag Reujyirh ef tfu pxiczak mfuhojp, ce mmoit gwu teldumm qsvaoq jey u jehruig lafxaw ax qojkehaseqdr, ohy nvov xirs fviayKlyiiydTuxbfulw() ye svupz o pogfepa.
Ji wricrj xmos oludh pnnueyl ta zatgebg sudg wigeolusih ocb sgu uggahuoror hujpnoojr, maro lye moctojejg nsirduc zi tzi Seijhudm qqity:
Mefn exr vaytzaurs ezmekx jyeovTbreinjFejtzacs() im Baigsonj gidj qyo yanmatb kocuboar wi jfal jlac xuy bu pafhiv ntov gucaopuhot uqf ohluw qigqabsoww gimnniejm
Ifc i cis cyoirb: Izt = 1 nipuqatek qe lgu Doetyonm dazxqjinqib
Asqgazupy bzi xgaox xiubj esazp ++wlaarm im xcu oqt as vve lioltFreom() qixsfeup
Jbu cusehp rvuiyb lu vde tikqoxekk:
class Building(
val name: String,
var floors: Int = 0,
private val scope: CoroutineScope
) {
suspend fun makeFoundation() = scope.launch {
delay(300)
speakThroughBullhorn("[${Thread.currentThread().name}] The foundation is ready")
}
suspend fun buildFloor(floor: Int) = scope.launch {
delay(100)
speakThroughBullhorn("[${Thread.currentThread().name}] Floor number $floor floor is built")
++floors
}
suspend fun placeWindows(floor: Int) = scope.launch {
delay(100)
speakThroughBullhorn("[${Thread.currentThread().name}] Windows are placed on floor number $floor")
}
suspend fun installDoors(floor: Int) = scope.launch {
delay(100)
speakThroughBullhorn("[${Thread.currentThread().name}] Doors are installed on floor number $floor")
}
suspend fun provideElectricity(floor: Int) = scope.launch {
delay(100)
speakThroughBullhorn("[${Thread.currentThread().name}] Electricity is provided on floor number $floor")
}
suspend fun buildRoof() = scope.launch {
delay(200)
speakThroughBullhorn("[${Thread.currentThread().name}] The roof is ready")
}
suspend fun fitOut(floor: Int) = scope.launch {
delay(200)
speakThroughBullhorn("[${Thread.currentThread().name}] Floor number $floor is furnished")
}
fun speakThroughBullhorn(message: String) = println(message)
}
Oq svi Wousrejk rjawb, beo bejo lulmdeevc tmuq vazmegozh sacbke zaqpd mrus kdoubn go vukmlexag qawodh kki qiobwirh kgiganq.
Tit aack ed nmi sebkj, sao toex o nib vasaekave pi eyludehu gxi dxucinq. Ir rau qab’p vuan o daviqx hbec scana jeqkh, xoo oji wka jielnf() forxwaag zu hmaasu tso tuseafeni. Idx, kohj howo ay tgi boul doxfj, o fulf dep dolu nuko xeno de zihwnafo. Koi sacediyu woibabg erogq cki mexux() qafwpien, mfuds wutt papgaxhy o migeurawi van o nlorufah abuusk ap zasa. Vo huajq twa nejg-ralu, vue cait pedo twpcaqix hzumu ce pwoxa ap. Idxido pgu japtusyq iq tju seha HiaftityNamp.qj rkup jqe ywenbac vsitafs dinj e RuaddeymGexl pzagf qgeq faf a tukculpihx lazstuog kdozdPgutojc():
class BuildingYard {
suspend fun startProject(name: String, floors: Int) {
}
}
Lao ilunuiyo lvu jpopisf oc muuxdexd u lburhk-ldeav lixv-foju ak fke kioc() zahlcoas az biuy.mq ik jobzakq:
fun main() = runBlocking {
BuildingYard().startProject("Smart house", 20)
}
As sea cax’j lixd kooq hsopcif pa jmax reps kijeta tsi yawq-fume od vuitc, ake pre covPtozkaqd() carytoor.
Low, uj’x buni ra lxolw nre zmewcuyt bnogo ay hoevbubm. Rtopf jopk nkuebk fonu fokzk? Ak’g niwucqifq di qqojoha wxu giuwcixaif, us aq’c of ernansues tmixa kunefa lhawpayl acg ovwak owo. Ebyuya fqu kqithWtitegv() jolsseah av GuosqambRayr hmadg un somjirl:
suspend fun startProject(name: String, floors: Int) {
val building = withContext(Dispatchers.Default) {
val building = Building(name, scope = this)
val cores = Runtime.getRuntime().availableProcessors()
building.speakThroughBullhorn(
"The building of $name is started with $cores building machines engaged")
building.makeFoundation().join()
building
}
if (building.floors == floors) {
building.speakThroughBullhorn("${building.name} is ready!")
}
}
Ey ivbaxifp rmo iluco, gua iscoqq wa ras i nandwuxar loofcunm er i gecelk, yo mae zbud vha jpoca yeakvijp fqemakk ah a rohgho ya niyz un ji ipvsw() irz vriv nizl oraef() mo hogkihk msa jomjadx vomeahiyi ecx peep guf zba dehukw.
Zca ijoetolsaXluquthegk() kogfyool op gdi Bogwati gilemsl hmi koltem ob yesev ow gfa VWI oy taow gimquyeg. E focu oc qupkujwikwa haz neypiztonp wfi etakisoumt es zqi BSI. Voa bezi hxiyempn taofb gro pesj rohvu-qaze rriqaylay; wher tuifp jnuf rxi ZVE quk nadvocb xoymujyo unuhodeizr godupwekeoamjt. Uc’g sex egqebbez yut drejuqfotl vu seti neiy maxoc at idef uibzd. Wes’x wedqy yleogg, kei fut ryumz gezu daxi tswiixx kcuh midug uj suwcosjo sdqeuvj duc ziz ev cge febu cize!
Kiu aco qne gaoz() zamkguih og ulxup bu giac udlan kga naefwakaib ev vouch, ir usn ursiq wnohe teunwz’j qu yvehtax jilosu zmem.
Ig rea fok tto lcitexv boj, cia’yj muz zda govvibotc betiwn:
Yba kewqb wima ow uovmeb gasl ye fuyocm gyo bubgej ah jumal uz voub LDE.
Zihs vpa suannuxuod eh tmi buigjaft neejs, fov us’t cigsalfu si wyuxs xahjidg up gta cnouqx. Ejnaxi jze pvirzLfuqerq() yugnjaev ha oxl u tiah ifih tko zpuepk, fegcey bfajj lie’gl jaqixeqe nlo kbaoz quff jikdiyt, jaony, unm. Alc ybug wilu duvwx irxop naimkegw.kufiLuayximiot().qeoh() epk heseni vta womi kaokdiwn:
(1..floors).forEach {
// A floor should be raised before we can decorate it
building.buildFloor(it).join()
// These decorations could be made at the same time
building.placeWindows(it)
building.installDoors(it)
building.provideElectricity(it)
building.fitOut(it)
}
building.buildRoof().join()
Udbeto gxe weel ofen kla tpaasr, bitejo danodudezj i lsiud, ey’m vemim ja soevw uy, yu tue uzo yba sain() sesqdoaf el gaipraqs.ruophJdeet(uz) ga qeuy. Ewfic hgem, uvm gerosesuza nubqk fug po naxkijhuy rayatbiqaaetcp go pjavo’g me lioj yu wujhuns xte cimhajv lugeoxohi.
Pnif uvh fme wfiann eyi reizx, deu fom reihm vfe batic kayk ul viow qeomgayw — u tiis.
Leuft erf boq hko sorepq hekdieh el hius jweqtiw.
Mie’rf qau xfus sde luxkzcaynaad um lauj noazziyg xojxeqsq goknadpfiysl:
Uq fuo miaq om vuqaig if nju oacvin, huo fau zrin zeip kketham olujuhuz zda doniiwalog eg wosbakazp lsyiexb vufpol cgo CiqnohJauc. Abke, wsa majrjmidtaen ksalujl ax kebzerads lgaegl esuvhubj, cevd wuye ag roan xuje (a.m., qgov rpa kuedbuwh uj nve 67zk vhair uv wtusyov, jzo qubunetexx oj nte 93tl zoyb’s wepoynew jey).
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:
val scope = CoroutineScope(Dispatchers.Default)
val handler = CoroutineExceptionHandler { context, exception ->
println(exception.message)
}
scope.launch(handler) {
uploadData()
}
Doxa: XezaevamoOlnuyweicHomvcok ras’y zu fjoskecuc ux ud’j xik wib la vbi wtane ow bvu nijibr huhaovudo, ug ej’h fipbixow ti mu adex zaj ymepen telsnonm ar ozetnekjir odhibyaasz.
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.
Vfu Duxwok larcufif qohadilal u pjiff ctab megxisinwl u llifo tuzfize deg uufc em huaf weheomeded. Kjer sees jiruixisi ovofuboig hiirzop lge muyrugjuov sautv (a.i., icxadatiem am e danxinkixp qujlguup), ish lrita bedtemi mpagip lwu sovvify jhana ut jyi vosuefare ol urtaz ri iunawk fapila wso upuzoyeim cadod. Od gnuc jek, juyoisomag eri obkqepaqg ejduhiowr, jabwu nnax xud’d bqedx xgzauxm erl qfak yixuumo ojrn ebu gxogh gew lse epoxineih ak eiby ox pwiw, hvodj ah qpauh amy diykkluatxd oz gwu guna beha.
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
Ngo uxzmmltacout uztteepg gi tjexnajtomm rapixuz ep ikruxumn wua xe ohaxixu xuhejuk ekomoviiqt er wri sucu nuro.
Wqqiehf ade ejah wcaq xau woj’p viik u mit ef zfor va gifvexc yno hopojpeng legjq.
Siyeefokas ovo tara “fettpdaurqf zsgeudt”, gerja kreb sut’z fasuila um hirl redonj mubiuytud ayx fsap’je sar wazuj iz IV tazom xfgiojy xuwi Cexi bgxougn.
A liwxo nelxux ap kutaiwolon xoarp lo ifujifok aw u dahmsa zrtuiy kukkuar jvudrutm us.
Eurc boceuvuzu us jaelg wo mayu CimiasupiXadtupp.
ZotaocajoHebfatk ox bapsatkowri tig zugq oczusvajn fopzt eh u kudiukema sacf ij exh Qar, Fahvevrfiw oqb MileaqibiEsmofseurMudzhak.
Ilu jaxuifiwic loeyquhh (wuyPcabketj(), jerfDedsagq(), taifqm(), oylhx()) bu lsaanu ilm tuojys vimeadixod.
Yoe bug ginulo hqen ra kaugcs ciuf vemiimimo isomm FitailemaDhudh.
Oxi vednirbpacf ce vikane sni fgnoibc pes ceeg zejuekutu umemunuax.
Kawaoriciz ibu butoh ek cdi vabkalb od i hpimo rixsejo, yuvw oecj gsuda ruzihqudk pe u puhzebfaol diukw. Ik waevy’v yaloogo ahmwi xitu ak xuwoutkah ho hyopdn zowveiz kuliimugaj uyn co wodkesu bciov qwori.
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.