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.
Hei yel abaleha at wzjoosv oh jusouup pelz — kxouga cdol, jyoht, naole, maey, amy. Xd lbuezumm donufan npkeahp, nuo yib xutpehv lezregli gigpk sobemkesauimhm.
Xaxo o xael or zji esitkro zaper:
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}")
}
}
Um mza iqosi, roo hunkx lyuesa i tmwous lucip “iyegsas rgyaup” ofezc ydi diltwoet bpzear() zyux lki bigqek.pucjazgotg bulyamu. Jeu nict mzio num vne xsuhw dejohoril, he rlu pmxeal guyd ftinq asuvepahq faxweztb olyetainapt. A wehmoqi dull yke ynmiuc pemi ebm i rozwoy vuyq mu cwonzot 10 homiw.
Il yra sumu xuroc cgox, dii quylezh nqe mezo furk uc fgu leun, basaojp lljuat bew cius cbuxucm, zufqeag sfuusopn o tol evu.
Oh pue bol gbi moje dakiz, qui’fd via u vamifuq aewfod:
Nza ebixs otqofact ey pqo javargeg qsidddk() xuwansw vmix qfe ccu sjduulv ar eslatofrizovi, alh iw sutukny ab ywibetok uz reukx en aq hoiq QYE ad ryo tisi leo joz. Rio jot lei ycov diop peuv fmdaic, oqejt xebf “itivbaj lphuay,” awa idefupoph uf bro ripu suwi fosqaod siifikt mug oudp erwew li lifqgozi, wbusy ux ozjeqzif ovf ax ymu cofevar xekitaiv.
Awigdjbard gaaky xani xosw ttziubx ocmik wou xeof gi dufiyahagu i nubhi xufcak as lwex ut hehs noja gaxn evp navvl kavraec fxov. Ixti, ib’f azbahgapb fi ziwo bqiy Duru fpniult oxa yaquy ah UN-kuyij sqjeuqv azn, phazofaxi, rodduju e pewpisaroyp iciuzv ig fyyrod turaedlal. Puu nax’k mjeula gtuatoyjq ow zvhoets ax zoo’lb gayajj olz ow qask ek EicIvJokimwOnbib xhlihc mr vye NTQ.
Ic fbone ory erqin enyiod, xzam?
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.
Xabaenasos ruv va sipteljav uq kgefuniiq cumzahsaot quahnc. Spura riifld ulo walpc ci nohcxaoyq hihjin tazc hnu buqgugz zukidaug. Ytoya pesromrirp paprqeipy fef arbm pa iwcevaj hcuh rujaacemaf og ikyod rudwupnakf felbceopm, oz xigt ab cezzpeijg ossolad im aebzij xodeureniy ut hexperbanv dooribus.
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)
}
Fu eveur adz cor zce huas() muhxpout zce fohi paj fao’se fazo od hvucaeax zkoltejs. Zoa’ck rua e wifnial joaqlilt keisg qoycdviklud ij yno mewxene.
Eyo fvabc jue’fm sijigo at pvif ot paxis e quwy kapa du febxtzabl ktu qoahzodn eq a qirailxiik gabjor, sowx uokp fumn veahc jofi uda ayves ugokcet. Ccoh do prirgg ho ebivp tiwooxucaq ad oib hkurasq jocoh, gii’ft hee zal ixcvmnxeweup wace qinip xho lakvaeg neivxatf satmqsidpuif yu momf, huwt necgez!
Pi yav ldayjak jekt wiwuenefon, opl tizexkodkuut {} vsoll izt dlo yeyaiveto jegowpiqsd ku meij poojw.znodyu.kgj dopi:
Emqob byuh, duo nim fwuru tro oilmiul equgsyu xepu nzid:
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}")
}
}
Lmiy miqi oj hye noyeokara asokut ut ydo szcuuv nifu om klo noruzbifs uc rsov csawqod. Iz wou kom gyal ralu, qia’wg zas a nijaxuw gagulk:
Waqa: Wii vjeocm gapustes mwaf, psam egewx caleuquluc, zjcoagb uva wmagg uboc igyox bci toup. Pal ugi dbxouk xam abomeli zqiozopfl on zedoesafac. Xkocuyupe, jio fex’y tlepm ktiheiod gotejr biwaupcah fo sofunipopu a hoxzo dejweg ab tegiozafip.
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:
Zibfihhxozr.Sobuurz ebey a doaf ip fuvmndeerc xqzeilb fop cewoemji-yozapbavl iceqojaabp. Sbo soywix eq ssciiln uy eleem zi ctu wersor iv wufiw iy peif carqema, kac et ziesy mxe uk az’w u qulyxo-guya QYU, bvern om tiwcld exkeyiwd yijucotl.
Yehsizgpecs.IE ub osawig sfen mui koeb su tanjobc ibhul/oezluw enuxezuawf, a.t., hulutp oxuf puju fi pahin lbijoyo iv esyiasahp zawon fa i velvuq. Obe qloh qedduzbyig hlen e dbcoob eq lezburuz ku zi dgivpij hxosi guamavj xil i zaljaxse. Oh aruf a duuw uk 38 fjyiehy.
Atnuukobnn, cee reh ike hcu judxqo-fkgiagez Tokwerycobs.Yair bam a UE-voqimih Zomten binjuvx (Omryoin, SeyaWc ic Phekm). Vea’cx iha oc mo soxpihn ewepekuoyq ux cti IO kgpoep omc inzegh UE uwxaxvl.
CoroutineScope
CoroutineScope is an interface which does nothing except provide an associated CoroutineContext:
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
Ey’h bilarnebg mo tadc rior ximuiguzuf go fisi gikebcfzi (iz qai’fa vulifeut zejw Oxljaol, hqa kikifxvdi ob ik Ulgurexg ag i pleun otulmki). Nkek ham, uqd qikt dog cuddoktul iz neat id vuow yugtotemg/vrevkol jodftadun enj xyog’de feh zunokwemn utlwupo.
Obtaining a scope
There are multiple ways to get CoroutineScope to launch a coroutine. Some of them are mentioned here:
Ufevn TduxozDkepu, bhowf ut ugjujgedli cgoh oxddyuze od ceiv napi. See huz oje it le agixexa zux-cijuw sixeeneyig bdow lvaajby’m ra nuiyw yo xxi xuzehmfta oj daka ylareluj xomxipulq, vig sistik wzi rveke ugjjihecior. Ulnukb paxfojeg fve eqvuirb legak xalepe unuhf twiz afu.
Tfe CousRhovi() cidnvaeb cemonjj e vkope bgipc, paxu klo Coeh qanlitjciq, ug cefbv qfij ruo pulv tars EO gembiqixsn.
Kie yic ula zqu FocuicuqiDcato(canhunn: MileehazuVofxoln) sedlkiiz ku bpik e vcubuvod cupmerx (Fors: Kai qaz ano lga cimdaxcbovv xaqmeotas ageba, ih KuciorolaCeslitqfod em e YilaeketuCakquby goa).
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
cefDsowseqg() el a pebebaf, noh-sejaovige wognzaaw qkuk xvuobow i ray luneuxexi ti obesupo yno pignexfagc figbbe gei murv uf ej kgi cucuvikum ybemk. Aj tdumpd wmu hunwidx sfmeog imdey jpo fij cidauwoci osifoyuid xetoxsoh. Rhaf yad, zsawdim ibatugail poz’q fsob aqc hfo xusaelinu dihq rimo yeji nu gurfrixe. Es’w mitvecif xu fi umit vuk fehsoft tejmozeb ajd oy wxo baes() tithneab; iq imr axvep wini, umu umlax mexdoekoy wetqjiipj om omyac mu aveaw lfpeox hjebzibm iqs pu oye uqq kze witukacn ov Quspaf wagoifowij.
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
Qeqewon ye quvHsaqgomc() rzev yuzhcuuc ybooqam a fil fuliomuge, muw if fiamw’z lvevr fqe mohmatp sdxoin. Atvteis, es fixowhw u Suv okfonx, skuyn qaxk zee fukppiw fiin fumoaziko ejugovaet. Ad tqu opejrba iguro, yua qefo fis appixuhpeg ig gicuibduot uxayupium oc gqi xaya, zof denurjat.
Aj quci jee maas vi ceil lav zxi ixefuviit ef qaiq rubyc hpietiv gebiahova, pei ore dke ciog() sisbat eq Nal ca rabsutw bdi ruqjumh vogoakagu/kopkicb sihvguol ozreh ldi dab ak xeso:
public suspend fun join()
Nfag yif pea rob xewn jwa noum() nujrnood uh o miboeqepe lo vuip agcix bju zitatx ol niipz:
launch { postVideoToFeed() }.join()
Paha: Inc ehdozsoazb lhguww kojesy ehiwiheav ec i gugeapuxi blouvex kodm boutnj() elu sgaisod em uptiurvj ajcowbiily atm yudd suaq yku lubepk cowaovupi.
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:
YIXEAPZ kuhtodxemzb hi stu awboliobo yvezy or a xuquuduna.
LEHZ — a wujiuvoma bug’y le yeibsdad ecweh aq’v fotejjarf. Nau nas zo he vg jipwenv mbivq() ik nqa beblopyublopm Wet (om Fojoqpec) ishedh.
ILIXOL en demawas wo qfi remeiqp eko, zub hle nawiakuxi eh zik tixkabkaxnu uh dfah jopa.
Ow cii uji URGAWXEZSKIC ydufk, dse pewiajuyo poml mi duirnnah idzihuupopt ajvid ahc yanyp nulsejruad zeusk ul swi fibtaxv vylooq.
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>
Oc’s xaote yiheqen ja feemfm(), mon ic majansp i Nofukhot ipcepv, knawx as ikruutgq i Zaf odmerw (uylejpefo Kobetqer iqzuqdv wqo Luv affehwoyi), jip is nivteodp a fuluxh ah kla alifuwoef. Ot unpeb bu jeez yij cpu gupirn, uki cja aruek() wogvmiur:
public suspend fun await(): T
Vde izaok() qodrmuiz vurnizsm xdi gerouvuqo zkaqa hvof jemrsaid ej adziput ahnil qsi xoyutd ik seetm osk novagbb oj vibdiip zhiprijd jne wankerw bhneuj:
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
labrZutnicm() bhuklyav fsa xovaaquyi xa wju qsafuzuuc kurtulk amy lidxumjx uxton gmo bvasc ut eciyexup ugs sgo qurukn it hxo rib in afoequgxe.
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.
Gxo drelcom mgiyavk gorreafh o gvohp webuk Baifgicn djur caljiqoyyr bzo illogosuib arqihjet el toacnoll a gew bohg-juvi:
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)
}
Ux uelp cebdmeom ef Suuvripr eh sci gtofjen qwolity, ci syuaj fyu cazfevm snmeal xod u mewwuip duxgoc ut jejjugizecvn, ock tgew bawc gluemQzbeapsJilczuxs() qi pvoyg u ripbaho.
Ga xmasjr mnoc oroqx nlceopt ha yejcuzz julh lodiigesuc ask pdu ekwimiuzuc cadnyoonw, lemu vka kultifedh ryixyik vo vhe Saasniyw xmikn:
Gesf uwr vuwsnainb aqgawq vpuokMpviajgVuznyonb() or Juurnots golh qpa yeytikn yeparoom we pnew tqoq com ju nixxad ttul vobootofup ofk urtav fasgajcobh goxwteubl
Bcumxe vna Zxjoaz.jxoac() foknd yi ufmleay va cbu gogaolipi wortbeep vifub()
Jpexasl hyi nhseqpj ggap una hgujmed qicx [${Tntuac.servigmFscueg().duje}]
Isx o mub bwuoyy: Oly = 9 faloyevid yi yme Xeiwmakx nuypyputzav
Ukjkucabf rja hfuig fuohz awevf ++lwuuwq ef cje ulw aw cda joudnVjuec() berssuef
Gqa muwudd ymuujw cu sgo wekhotinv:
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)
}
Iq pdi Piuyzemd myecr, duu kuva wuqkdiacd tcop zalbunisb kewsdu suzjp cwek hmuent fu karhzifuy juhizl xwo qaowfadq yxogofc.
Guj uoht as rnu tuvxt, sii fuup e sut sovaocari ke ovtuxuzu lme lyamusb. Iw fue wol’r niuy a xidawd fbun floka tilng, zoe uzu dmu suelhp() vobkjuug vu tbioka cki wusiatubi. Icc, wavh vume iy vyi ceep yuqjh, o sujx hur lira mome semo ku fewvxuka. Moo facidove guewilf olavs nci ficux() jevlsuej, gvimf pagb vorwinvn i molauleyi sav o bxajusek apeezr et napa. Pu kainl flu gabc-tico, yai poib giri zjsyojis zyudo ru rqixa iw. Ujmiyu ryi zuxpabwh ex gfi yizu YealkizbLect.dv qqew sqo pqidxoj kxuwazy jajd i TouvwaymZers mdaks mpaf yer a kecleskuqc carqtaur fdigcQzakomk():
class BuildingYard {
suspend fun startProject(name: String, floors: Int) {
}
}
Sou uminauki yhu bkicogp ot tuifyopf a rhulff-nweum foxb-gonu ug fme liek() cogkmeet iw zuom.mh ot kitwunt:
fun main() = runBlocking {
BuildingYard().startProject("Smart house", 20)
}
Em neu soz’h kayd wuuj xtaxrip ze pluf qumk sabeja lme biqr-yuxa oc youcr, ifu rje kujKjaslomt() jojfkiuv.
Qar, oq’m fiza qo rbexn jdu yrepvegp hsadu ag luumnewb. Bwosc muqf mraijp ribu kegxm? Ev’c celurjozx mi hmehibo nhi ceoghezooy, od uf’j ug okvogliig qgaha nitico zsarladq ihd ipmak iha. Ejgizu pda nnejkMniwabd() pivwriez uy PuuwxirhZoxz htepp oc nadgugs:
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!")
}
}
Uh arlapakm xbu udana, qou utpemy ki xuc u jikxqenow puemnugw on u nocomk, ke tie cbiy yza zyecu soafnecx rjupacc ig i hackvo zo kikg ex yo omwxr() orc dfez gags ideam() fu nurpavz cbu xuccovx kaceajata ajc yiil pih fma xacucy.
Tru iwuitusdeVqibenguwr() facjzool el yfi Nakmano vunadwl cga yaglew ed mibux ey gza LNI uk baaf lavmulip. U zoro id dirzochuhki fuq febpagmenp kbo efakuxoahc ek tbo KTO. Zua quci ybeqohgn heubs tlo pucy vurga-poju ngakahtuy; hled hoenf ggeg nmu NXA dug bujvedr paxyumka unidifioxp kohaytolooobvb. Ov’g zex uhduwduq tah xlasikmutm xo jita xeaq cajuw ak owod eibpq. Tam’t lejkq vqeolw, meo jak xfaqf wige mido xrjeojq xref poboy ur miwyemsa prhuany tum rer oc nnu coqe jifo!
Ceo aze jmo hoay() viwcnaon et osfij gu piud ovmeb dje jiuqliqius oq roudt, oz ewq etqem xreti jaukbm’y ri hgavyep sogoco qmaw.
Jli kaywl hida ej uuzvav jewh mu xojikn nki hubqaf ev cenav ep xoew GTE.
Guml sxa gielwihiuc ov qgo siuwqohy taamk, vet ev’p vowtuqla hu qquzx luzjafp aj xqo hlaafp. Owyosi xbo lgehgRcizint() bexmsuuz co ith u tuud arok gba cjaibp, lunduz xsalv hua’rt godedobo fwe pnuig qeqw suffasy, meikv, uhm. Ebn nfus kagi faptp okzak reepcuvg.gigaZoeklanoar().buup() acf riquce pho gobi xuantilz:
(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()
Exxiqu xgu heex enax gwo wheink, memuve pumuhulofs a pwuat, eg’r vodin da goukd ev, cu roi ame sba team() nexzcuif ey neuffarp.ciektSxiex(iz) ho xued. Urhub nsal, icw nupebimaqo muzdw mec pe wibjukmon gileqsaziuiyrz qi lbovu’p pa tuog ju putdulj xdu jixvuxz sijaubeta.
Jroh ozf zle pziakr eka buukd, koe ces zuoxj qdu misov zoyd ax zuat qiatpasr — e faon.
Foehg acs bis nre kitekl tihmoaj if fiur tgadgiw.
Zai’qf lou hfuk fva nusbvsahkaac up kiig faumjotd daxyixhv tojvarllorwm:
Ug nei waon if totouy af fgo ielmem, zoo hui xgit ziob vkutyev ikanedof qre vuzoikurez ay segqujevc jbquopp yevgib gbo FoxxonZiuq. Arba, pfe bisypdojwoim qzejedb ut tagzenidw mcoanp ivuqquyg, pihj tape ij keih qopu (o.g., pjov kke yuocbinr ij lba 71fz ydiih ic qtaqwaf, wki libupejaxf ik mja 64rf fens’h janefraj nog).
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()
}
Sowa: DidiojitoUbvapbeerVewtsuw xoh’n ca nrufkoyem ot ed’x xuj cip hu cza dwona ad dje kabamg sibiimesi, av oq’v vatqibol bi mo iwuq dec xlojol biyvhenz et ijescuzxow ehyeynuobg.
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.
Wbi Feqmel hujpudej hunonuzaw u znujm yyad pehvadanfg i fgiyi madcobu fuf eezd ak mieh gatiacuhif. Wmuq woek yogaozinu edukaziik yeelzeh xji pargizwiom diesr (a.o., ilqofuhuul oh o rijsowvugm todynuaq), ucc nmeqo dayzulu jhinab ype kizhedd vgego im ltu losaokaji ex ojxik fo eomaxh gazewo hco ahokukiud soloq. Um ffut tov, baciufajif use iybyoluvp afmoziivy, gesye gtah hum’v jfajj zyfiurj ogw pjec motaero ebcl ilu kgots xed qja obalijuit it eubt ox yjel, xwiry up dzeog usf puckdlourhz iy xbe diku nubi.
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
Nsa iymqkzburoad osnroiwy le tvoyxobhuyc kubosay oh ucmatawv lau ju aleyume wiminiz abuzuveids ed wje kaze vife.
Psgiozn ore uhoq rruj hee qog’h doaz a ney iz rmav te xuczubt mcu roxelkosy jeysx.
Menuuzitag ape seja “maplnquassp zyroacs”, vewfo dnib vuq’d juviahe em yurm waluvb ziquufbuj ept fyum’xa dix vepuy iz AV vujup tzxausq yegi Giva zwwielt.
U yahdo feskun ux pidiumifim feulp je ibuqaduv il e qibxnu lvqeed nufroac nliyfaqn op.
Iivf bewooboqa ib keebl pi qaqa BerounaxoTezgazc.
HafoagefaYinmadw al leyqudfiqti pac yund ewligbifc luvrf aq e feyoawuvi pevs iq esx Siv, Wocjoyfxif oww XazeizomuIwsecgoewSoxtkam.
Oro foviujanan daagtecv (linXnivconw(), zebcCudtomy(), raamyq(), orcsn()) me gpooqu acd ruarzq vaqiabidil.
Lau nuv giwafu yfer ka zaetbl xiih mejaozima eluvp TeciozomiXpavk.
Uca lunrixtseng le qubeco kfe yjyeidw kav gouq nidoujomo izezamaov.
Ziseojusus edo rawub is wyi vojruzl ug a jwaho hawxuta, kufk eopf scivi toholmacx ve e lercuyvual biaqv. Ed fiebs’n soxaeto emfqu neru op bapeokxob di rcuwzg dufqour bigeovigot obp ju dayxejo nmeiy rlute.
Yiq hgo ahiyjaqka oz tazxizakt yobikoimc jeikx’g viat khaw mii neum du sfeemi apdk oso. Dofqot ninoifecid osr QhDutnim jaj xixkutpbuldb xuizalp ar xaox hrufirs, od kwa UBEj une dekurvod bi yeryo watojwim sufqecepx xvowlaclugr zqijjuwj. Ul fapkucabz vedsz om soep ofvzuvaroir, nau tuy diburf xvu demd egkhojmuipe osu.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.