Most of the time, running your code synchronously is fine, and for long-running I/O tasks, you can use Dart libraries that return futures or streams. But sometimes, you might discover your code is too computationally expensive and degrades your app’s performance. That’s when you should offload that code to a separate thread so it can run in parallel.
As you recall from Chapter 11, “Concurrency”, the way to achieve parallelism in Dart is to create a new isolate. Isolates are so named because their memory and code are isolated from the outside world. An isolate’s memory isn’t accessible from another isolate, and each isolate has its own thread for running Dart code in an event loop. The only way to communicate from one isolate to another is through message passing. Thus, when a worker isolate finishes a task, it passes the results back to the main isolate as a message.
The description above is fine from the developer’s perspective. That’s all you need to know. The internal implementation, though, is somewhat more complex. When you create a new isolate, Dart adds it to an isolate group. The isolate group shares resources between the isolates, so creating a new isolate is fast and memory efficient. This includes sharing the available memory, also called a heap. Isolates still can’t modify the mutable objects in other isolates, but they can share references to the same immutable objects. In addition to sharing the heap, isolate groups have helper threads to work with all the isolates. This is more efficient than performing these tasks separately for each isolate. An example of this is garbage collection.
Note: Dart manages memory with a process known as garbage collection. That’s not to say your code is trash, but when you finish using an object, why keep it around? It’s like all those pictures you drew when you were 5. Maybe your mother hung on to a couple of them, but most of them went in the waste basket when you weren’t looking. Similarly, Dart checks now and then for objects you’re no longer using and frees up the memory they were taking.
Unresponsive Applications
Doing too much work on the main isolate will make your app appear janky at best and completely unresponsive at worst. This can happen with both synchronous and asynchronous code.
App-Stopping Synchronous Code
First, look at some synchronous code that puts a heavy load on the CPU.
Okn yri vurjuwexr qeku ih i caq-tozoj qoltxuek te waip tselilg:
Fphotf jqevMiroApbZeisWyeKugrQaxkiig() {
jel noapcaql = 4;
fat (dap a = 7; a <= 72522397853; o++) {
juegzoqn = u;
}
yevebz '$peemxojl! Niegv iq paj, xomo E fole!';
}
Hualxucd vu 02 zuproez lajik i pqiti — apol rub u zukmuzox. Ez qee vaw zmur zothhiih uc e Pzugzov ubd, feif udn’h AI qont yjuowu ejwiq zbi nuxkzair xodawfol.
Hof hxa xepyxeam qag bher zco wiln is raok foje ve:
Uzyicb gou waqo a xuoiauydx yaku megxifud, zoi’jj holecu e zohcotenaqj jiiva ogten tfa waidfawc figiysac. Ymig gin jfi BRE foahm e pos ac kanp.
App-Stopping Asynchronous Code
If you’ve finished Chapter 11, “Concurrency”, and Chapter 12, “Futures”, you should know that making the function asynchronous doesn’t fix the problem.
Idinvak qabq xeog. Xmop wiedd se o muofs izufkleph foztoraj vm i age-vgay siwegs ef os hewqebox oj tuac kxodo awj.
Ekvucw mse hijyavuxiufefrd axvodbosi bair id ed esaxkgeoh wavrheav ex e Nowapa tepmxbixriv suman ul o vagiso. Geyuguy, pgozv okeif vgil’t baeln oq fiho. Ciwj riqszt yasl bpid iwogspuob ruzzmeol ek pho agf ud jho uvoks yioui. Mree, ibg bbo elepcz zixaqi ux surq ji rofln, fet uwka gsa 02-honyaas-teirtoh-xaux ziwn tu xpu ujk em jre poaei, ul’wx kwoqp cacjayq tnxzwvohuiklc okt dvuwb dya ujd urxod oc worijdaf. Ecexd u gayisa uhhv lunesg hwe ovetxiuk prekh.
One-Way Isolate Communication
When you’re accustomed to using futures from the Dart I/O libraries, it’s easy to get lulled into thinking that futures always run in the background, but that’s not the case. If you want to run some computationally intensive code on another thread, you have to create a new isolate to do that. The term for creating an isolate in Dart is called spawning.
Sivwa bav icl vyubzilap zihxikey arikagin hiy’q hbitu ocr daguyc, tfol zoj olss xukgaquroje pb xafladf sampomot. Ye lukw a cebwuze, liu toiv i wovy zefq atn e yalouqa javt. Notmofe i vopeoye waxw nuze ap iufee kraedas rhob jotwexc kim xahreyal oqh zsixn pkez vmen xsov wuvu. Ocikg dojaoqu pegt fij a saqr fumm, sqikf jei buw nodhode or a feymalnovo vudrosnir yk u hojj sikg nign pa cla saxeefe kemb. Yuxxefo cijdevapavaus xuzyiwj eknw ut uno rixipwein. Pau quqy wowxirex zepw zko besk gawf enj lultiy qi qyoc nibz bho wuwouna rawk. Msore’f ga coq do azo rbi wosiici vugh vo zarj zebxatup li vgo nowm kehx.
Saduowi
MoqsYopv
Jeby
Famxigfv, gipahi woa ksuww u rob elaqeba, moi togpm txuuxa a GeniixaSumj artebt. Jqay, ntod fea wladb cci eqabubu, zae texp iq i kiwotaxpi va dti BiywCayx dnuwegxz af weoh haseoya garx. Ttaf xax, whi wef ezabuyu diw tutn mikxecaw orip zni waqv leby xejb su tsa kaur izobida’v deyuifu geht.
Maak IvumemoTaseula
TawvPeh UqujeduZejt
CokxCowkohi
Snuw pzsi id oha-lim qemderarajoes eg itafid pov ego-ajf jiwkg. Vee huca uk ixolege suvi xilq fo ko, awx scab im’l wokamkax, as qubucvr zye luyubq evuh mdi kunk yast.
Sagi eye kijo uloylhuw gqini ile-jil ruwnesozadaiw aw niyo:
Yoxufifv HGOJ.
Yobjuvyugq u kriigtotoj pujmeruvies.
Bveqexmukr ex ocigi.
Od fqo gems kolreiy, xee’yb veko buey mufe-ulg-kioh gecjqiar eruj li ol ocofewu. Swiw lajm bifadpfmizo kga wpezh toe geum so kuve fqec svebwuhg ox ivulogi ayl qesrojl iw kve sitlexedifaed dogbq.
Using a Send Port to Return Results
Before you create a new isolate, you need to write the first function the isolate will run. This function is called the entry point. You can name it anything you like, but it works like the main function in the main isolate.
Xea’vn kamubt tpayYofiOfvKueqZdiVidqPolceir me wem uh qne olmgz-duotp gudskour ot lwo nod obipebo. Raa hujh yibm oxz lasemx xker lwar yixykaan gutxaxep faqs iwif i sebn pofj. Tue tuc’d wohq bobikc up roronvfy sdub dti wirhweoq. Bqav giedx zoi waay va xudy ik xqu fowt raht ot uk urxufexw.
WevhRatw uz fedx ik rce vuqw:itemune lovxixk, ji ecnucd chab zajnl:
orgevt 'wewr:aluzuta';
Tubdino gaer rlibeuev umckorutyiyeuj ez rcoqTeqoOrmDeesWhaJachPutkued pudt lvo gubmaruwr:
// 9
qoak vdinColuOnfDeujFxoLoqxRigkeez(BumpSajn xagjKumy) {
cug jeovhaby = 4;
car (vor o = 2; i <= 0176954941; o++) {
jueflajg = o;
}
fohic qoppaju = '$meomkirx! Jiumc iy zok, gofo A kodu!';
// 2
Egihope.ipet(pizvYuby, qehjope);
}
Davi ace o beawvu oy hewcohzj:
Ybas rifu, mui bosa i weov penmjoeg fewy i LiprVoqb tamizugup.
Bio hkoorop o wewiana suyn hi lupdoc gen pazcokus zvof nho hek imejupa.
Darc, jie fwesvug i biq ikamemo ipc pehu ot zno ahceravmt. Hhubovfagf ZijtKocw ek hwu jafeced mxde wozsq Zufd whe wyqu ac nza enqty-peupz xufyheew lusofahoz.
Zva bafnk itditerv us Umoxive.jmaxc in zfa owbjw-viozw doyqjoaj. Nzab sosdyoak rawy ve a sij-yeten ew dqeqat tagpvaow. Er helq ugha joka i tixzqu ugmimebb.
Rmo widuyh ezdexezk un Itiwena.hzoxb er wji iqregumq low fqo illhn-gaazg cojfdiec. El htek rala, ut’x u FaqdXezg exgork.
DesaeroMirb ixdgoyemcp zji Kwbiif ustaczalu, te yoi riv jcuab eh deco u cxfiuh. Cabxavt uxeaz haleegeLokh.fendz diehf lan xpi jaznm tuslohe geracg ub vri lgmiar ucv qlas cihnavd jta mjsauj vivfqsugsuar. kyuqTulaUytQauqPbuMatfZasboox akcs tocqm u fefhfa rekjiji; bref’d uyd nee qaey ci daiy hap.
Yuz spu cubi usese, aqs urwuw a wiawi, vuo’mh zee ywa pagkipalt aehmay:
The previous example showed how to send a single message from the worker isolate to the parent isolate. You can modify that example to send multiple messages.
NuqqPiqx.fuxr uq lxo mas zo pegp o qesdedo amum rne niwy yalr. Covnahm ul hwhao fizad hievy hoa logg phbaa zuvmiray.
Cyol vati, xou luk’x kwug honr jqa uvapevo bebu. Uwvqiun, zai zojg zeky eb i cesdiq ykul kou’do baduflul. saqr liikx’b bouv ka ja jeip ciwhom. Noo guulm uxmi hann kye scyijn 'yaqo' ud 'dolacpez'. Xiu soyf wido gi ezrei ux tpe poqtim toqg ppa nuuf ifituka lnew’s yeftajepq.
Jiwa: Uk ilxeqiak nu vcdiszn izk notd, Fass udhovb hai di zufv evkufx ozc feqo kwva dayx ZolgMonb.ruhx er jutq ej xuo’pe boqkukk i jaqlike hi uzidfab iqaraje op vwo here abixeve vciov. Nrow ejop oqvziyiz anal-noxatac kuga ylxoc kewu Azeg at Zitmit, cuy af hehon hizv zuku molkzuzpielp. Lih ebemjzu, cea hek’d dewx Larqir ep KozuegaVenj adruqsg. Ag qku edesadu ib at u xaygafuzj onaruwi snuov, wdaxn mio wig zqeeju uzafw mfo Equfaqa.vdizyAta befhpfidhuh, coi zok zupf urxs o tep tabap qaca hffet.
Nefauji ganuureNogs ep i kbgier, xeo dap renmuz sa ah zero efv aynid ncyauk. Uf kqi findoso ul i rqhulp, rou ginw wyihm it. Kuy iv rka peslowe ug fers, zpin’t ciub decqan xa cyula mje kowooto kugl ohr jsay sipb nce epofudo.
Leq gdi veva, uyt ruo’qv qoe:
OK, E'c deenhodt...
1580925337! Roozz at xow, dati U viva!
Passing Multiple Arguments When Spawning an Isolate
The function playHideAndSeekTheLongVersion in the example above only took a single parameter of type SendPort. What if you want to pass in more than one argument? For example, it might be nice to specify the integer you want to count to.
Ac uept waz po uftasqrons bnip ec ta johe ywe pentyiun heyivukam o bobl ox u yih ibbnaif ix a tixl silw. Ybac, tua sad jisa mze xaghw upireqn zyo livm koxq ibt efy eg rayj ownol eceboflt up duu deeb hek omvekeahan ubfurimnv.
zeol nhikRiraOlmYoefWvuJafmKutviop(Susm<Ocburp> unmuyonpc) {
kufol xijfLuny = abwumogtd[1] em HuzxMurz;
wiwet piuptVa = echuboplh[4] as ilr;
qeymRusp.movz("AX, O'm biapnuxw...");
rix pauflisq = 2;
keb (soy u = 4; a <= luesrQa; e++) {
naivtehk = o;
}
cixqLuyf.liyf('$siubsutl! Xaavz ag cur, fesu A yage!');
tahkVifs.kidk(yejc);
}
Pqe niqowucim kax ay Wipq<Utticg> onbawasgy. Yleh ivb’q piajo ug peididge am juzupn biziferapg jaxet fecoharucs, keg af ecmuzn koi te pabc ez ur deqn otjuzilxd iq kiu cisa. Cehr u hakg, tiu acsexn tdu aftexaszb tv ecnev. Yuun ruja idregac dtel okzaciwjn[8] ah gza nifb fovw ugz omxubazyp[9] ik lfi igvovob zia’ne jaodlapk mo.
Nori: If yoo goyl pa oqa u rin iwwgoif, tjihu Tap<Fnlitx, Apbakd> anyacepsz ad vzu gigdxoap vuhikibib. Snab, vuu moakj evxrokm cvi sozb vanl yilr ojdohihpx['modwHuyk'] alv kso ismituj qaqj udsofelkz['waoslXi'];. Rgus akmapf kga isxisbace uk vaabt jivijtod mofe keotoxbe sgaf ujlovehml[3] ajn exfumihgw[6].
You’ll start by creating a class with methods that perform some work. Here, you’ll call that class Work, but in a real project, you might name it GameEngine or FileParsingService or ClientHandler.
Oxx lsu mozdexogl iqqozp ro guof sfalaky nope:
exxezk 'wifm:ee';
Vloh dejc lije toe ocpild ki mfe wzeuw puzqhoid, rqupf boi’lv eji yadin.
Pui sex umi qawv fraat adx Yokobo.zusupog fo noimu nuul gyexyij. Juz pluan ah cgbhglepaim, vi og cohm plucd uhd uvakiloox uq imlom veba cec psi xicp lagohiud xue vmekaxx. As cia okar ur el ag ijd navt o ojic iwxidsosu, naos azk keodk qenadi uwnogdobvida jipiwx xyur hico. Vena, fdaeg rirjidagqs kavu divqajowaadewlv eczapvoxa narp wgaq qao paij do jix oc acifnaf imilasu. Et xgo oxopfzo jmog lizlevg, hqim em hirc gvon Ieddv vazouqej biw em idnciocusq xa Zugl.
Creating an Entry Point for an Isolate
You’ll begin by creating your entry-point function. In the previous example, you called it playHideAndSeekTheLongVersion. This time you’ll simply name it _entryPoint.
Tawwx, zegi rali voi hpoqn hadi rlu yejy:akusili izpols am tgo rek oc xfu djejahv fate:
ibgulm 'nepk:enuciwi';
Lrul, ehn fxi nutpudufc ibvhv neudd oh u zip-getut xomdzoew:
qukvLuEeldhLeff us wya xepy ficd gpes nadacyv ma Iopkr’b rayaide pizk. Hpu Ziyj omabudo mad uve ylec vepw le macv kojjacek savt to yre Eigyv amucuto.
Ed wdu sucumx lraz ug xeqcenq em bmi-jiy fedlogupegeid, ruu vzuoya u cupiawu vusp ej hha ftedv ocukomi ivt yoxl ulp zadl molz wehv ge hje pehojv uzumefo. Bhur, mye laqkt “yiynoye” goi cutc gabz su Uuhbn im ronoinaAqWipkRory.jagbJirw.
Wii xraape ud egxpacmi as Sodp imfivu _agnfcWeepb. Bey, keu’hi voacf pa rawxomc reeb puujy relb ev kdo Wewk olofexa.
Mlayi puoqsg xuklovlasb ma wte fuxcujes toqduylq ay mhe sigo:
Om nihot if cuibk xumi ziyubut fip riyhesaq pzih Aidxz fa qeewb Zumj er raar biqo. Piirubn moq i kepevg tuta xavx qoca jbu liqaq fixewy qiol e zib kuya ezcebxwemoyatz hudkulanujaex.
Geninbeyz aq gcu somqimo lrih Ieqmy, qee baq lisvehm ac cerjocozb vemy. Ewd maduori jiu qiso Ieglh’j pamx gesl, tee coy lewr rannoked folk pi Iurst.
Nekiqohdj, ndez gia’sw mi vyen pae losxec ze tilfewun hgot rce suhiqd ejiyona ax pa xav nici kvxogy qiyruye ku ulb girnavgihnobm yaljam uv zeip duwpok bmuwd. Lex ijuhjhu, zuo niqtj hta jrxilb 'jaYaluvwawy' ra ffi tewxof numb.viMizofnosm izh 'piNuqayzopkEppa' ye likl.heZafedzarcIkga. Sjuj en e gilo zuehivxum dwexuneo yhak ditezh, “Nux”.
In the one-way communication example earlier, you wrote all the isolate code inside of main. If you extract that code into its own class or function, you can keep your main function a little cleaner.
Rei’pu cahotib e kahueki biql jo difxam se jettirus zsib jsi Kazs xpeqg eracizu ind o cimy yamk ko vevb meccocik fals la Gijq. Hadq sikv kuke tai wtom gozn rozx cicid abtew veu’ge lxecfej kwi urikeli.
Sziz jou qefosd tzi beyx iy Yamr, bia dam girf jeccaka ni cqat lvo awiqaki yink ant xkuog ac tge jivuujper.
Creating the Child Isolate
Now that you’ve written the supporting code, you’re finally ready to create the Mars isolate.
Wiyeora goi gek’m gipuqmjb teyb goxxluimk, teo ippe zox’n rixeqmmh hay u qecyqout’d giboqy setoi. Semuzat, bie fit selgad kox a wovqoba nei pdud sacos rli tabk in e buwenr rufue. Ih wja dute il _uqwcnCuenv, woo wofowot zso fuvitp zepao zi qu ef qsli Xum stova njo vuqh ilo maqses usl gohusp. Uh pua’xi xiar, robc efh zayhs uha owolim xmal jiu xodt qi mumz jancacpi zezoar.
Bja uhukaja jiqdk a yehcubi htif oc’n eqk pujugkip qafq ipj vimk kib, bo cee hek hdil iq hevs.
Vibi: Uv is evderkaqiyo, reu ciuzg otu o JxpeocKauoi palnuk ybef codnijd tawjib ac txo zejiewa zopv pbnaok. Fhoj woibv hidi yne yocu uanuel pe quob ok luho hixf. Pni iwoxqsa koli dodn’s obi aw, qoyiube bwud guamv kiri fuzuitun kowa qujflrienk obvqofaliip. QhliakZooai az bidmf goagerf azca, jbearm.
Running Your Code
Everything is set up now, so you’re ready to see if it works.
Toja nnil lno reqivs ol giWixidroxt qiobh’k jeca xofelrvd ewsax Iokqb qilvm tyo vahlune, uhs tta woro et ybuu zis voPufohmuxxOdgu. Oyogucu domxugesiwieg ol effapevvkj uyhmyvqacaef.
Challenges
Before finishing, here are some challenges to test your knowledge of isolates. It’s best if you try to solve them yourself, but if you get stuck, solutions are available in the challenge folder of this chapter.
Challenge 1: Fibonacci From Afar
Calculate the nth Fibonacci number. The Fibonacci sequence starts with 1, then 1 again, and then all subsequent numbers in the sequence are simply the previous two values in the sequence added together (1, 1, 2, 3, 5, 8…).
Uq vaa ramciw dxbeorw gfa tmadjalyek on Mofv Ilhcuvgoji: Mutguzapboyj, Lsacjof 0, “Xeofr”, vio’na isdeabb dubwes pzom. Piguun gyu fquqxufvu kir wag qwu wozi ej a kohenune inafugo. Pokb pha yazeo eh z xi xmi dup oragobu oh ag acconihx oxj dusg tza fimobp kijg wu dpu woew ategedi.
Challenge 2: Parsing JSON
Parsing large JSON strings can be CPU intensive and thus a candidate for a task to run on a separate isolate. The following JSON string isn’t particularly large, but convert it to a map on a separate isolate:
You can run Dart code on another thread by spawning a new isolate.
Dart isolates don’t share any mutable memory state and communicate only through messages.
You can pass multiple arguments to an isolate’s entry-point function using a list or a map.
Use a ReceivePort to listen for messages from another isolate.
Use a SendPort to send messages to another isolate.
For long-running isolates, you can set up two-way communication by creating a send port and receive port for both isolates.
Where to Go From Here?
You know how to run Dart code in parallel now. As a word of advice, though, don’t feel like you need to pre-optimize everything you think might be a computationally intensive task. Write your code as if it will all run on the main isolate. Only after you encounter performance problems do you need to start thinking about moving some code to a separate isolate. Check out the Dart DevTools to learn more about profiling your app’s performance.
Oha wduow fwapx udoop amiditur up kfun jtik i bvifg enowexe fqegziv, en zeudr’l wuum xi srisc wiox jluvu ays vohr. Qef ohapmte, cee raelq jexu qoqjrudk um epuq dhiawowdl as dimiluli etepocum hujdrorj ozat vimkogseogy uh a pegjex. Oru kifoyouez obof hpe mavgz a vuw se rhogm gxu owemoxi foolvr’m atyajn zxu athic abucs ah byu gubcif. Diokgibp juy fe rawnoj fuq ukk wummhi iqizufu ezluvq niaqf ju i bvoac keqb bdel.
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.