Kas daro „WebAssembly“ greitą? – „Mozilla Hacks“

Tai yra penktoji „WebAssembly“ serijos dalis ir tai daro ją greita. Jei neskaitėte kitų, rekomenduojame pradėti nuo pradžių.

Paskutiniame straipsnyje aš paaiškinau, kad programavimas naudojant „WebAssembly“ ar „JavaScript“ nėra nei vienas, nei kitas pasirinkimas. Mes nesitikime, kad per daug kūrėjų rašys visas „WebAssembly“ kodų bazes.

Taigi kūrėjams nereikia rinktis tarp „WebAssembly“ ir „JavaScript“ savo programoms. Tačiau mes tikimės, kad kūrėjai pakeis savo „JavaScript“ kodo dalis į „WebAssembly“.

Pavyzdžiui, komanda, dirbanti „React“, gali pakeisti savo suderintuvo kodą (dar vadinamą virtualiuoju DOM) „WebAssembly“ versija. Žmonėms, naudojantiems „React“, nieko nereikėtų daryti … jų programos veiktų taip pat, kaip ir anksčiau, išskyrus tai, kad jie gautų „WebAssembly“ pranašumus.

Kūrėjai, tokie kaip „React“ komandos nariai, padarytų šį apsikeitimą, nes „WebAssembly“ yra greitesnis. Bet kuo tai greičiau?

Kaip šiandien atrodo „JavaScript“ našumas?

Kad galėtume suprasti „JavaScript“ ir „WebAssembly“ našumo skirtumus, turime suprasti JS variklio darbą.

Ši schema suteikia apytikslį vaizdą apie tai, koks gali būti programos paleidimo našumas šiandien.

Laikas, kurį JS variklis praleidžia atlikdamas bet kurią iš šių užduočių, priklauso nuo puslapyje naudojamo „JavaScript“. Ši diagrama nėra skirta tiksliems našumo skaičiams atspindėti. Vietoj to, jis skirtas pateikti aukšto lygio modelį, kaip skirtis tos pačios funkcijos našumas JS ir „WebAssembly“.

Diagrama, rodanti 5 darbo kategorijas dabartiniuose JS varikliuose

Kiekvienoje juostoje rodomas laikas, praleistas atliekant tam tikrą užduotį.

  • Analizavimas – laikas, kurio reikia, norint apdoroti šaltinio kodą į tai, ką interpretatorius gali paleisti.
  • Kompiliavimas + optimizavimas – laikas, praleistas baziniame kompiliatoriuje ir kompiliatoriaus optimizavimas. Kai kurie optimizuojančio kompiliatoriaus darbai nėra susiję su pagrindine gija, todėl čia jie nėra įtraukti.
  • Pakartotinis optimizavimas – laikas, kurį JIT praleidžia iš naujo sureguliuodamas, kai jo prielaidos žlugo, kodo optimizavimas ir optimizuoto kodo grąžinimas atgal į pradinį kodą.
  • Vykdymas – laikas, kurio reikia kodui paleisti.
  • Šiukšlių surinkimas – laikas, praleistas valant atmintį.

Reikia atkreipti dėmesį į vieną svarbų dalyką: šios užduotys atliekamos ne atskirais gabalais ar tam tikra seka. Vietoj to, jie bus persipynę. Įvyks šiek tiek analizės, tada vykdymas, tada kompiliavimas, tada dar daugiau analizės, tada dar daugiau vykdymo ir kt.

Šio suskirstymo našumas yra didelis patobulinimas nuo ankstyvųjų „JavaScript“ dienų, kuris būtų atrodęs panašiai:

Diagrama, kurioje parodytos 3 darbo kategorijos ankstesniuose JS varikliuose (išankstinis, vykdomasis ir šiukšlių surinkimas), kurių laikas buvo daug ilgesnis nei ankstesnė schema

Pradžioje, kai tai buvo tik „JavaScript“ vertėjas, vykdymas buvo gana lėtas. Kai buvo pristatyti JIT, tai smarkiai pagreitino vykdymo laiką.

Kompromisas yra stebėjimo ir kodo sudarymo pridėtinė vertė. Jei „JavaScript“ kūrėjai ir toliau rašė „JavaScript“ taip pat, kaip tada, analizės ir kompiliavimo laikas būtų nedidelis. Bet patobulintas našumas paskatino kūrėjus kurti didesnes „JavaScript“ programas.

Tai reiškia, kad dar yra kur tobulėti.

Kaip palyginti „WebAssembly“?

Čia apytiksliai paaiškinta, kaip „WebAssembly“ palygintų tipinę žiniatinklio programą.

Diagrama, rodanti 3 „WebAssembly“ darbo kategorijas (dekoduoti, kompiliuoti + optimizuoti ir vykdyti), kurių laikas yra daug trumpesnis nei bet kurioje iš ankstesnių diagramų

Naršyklės gali šiek tiek skirtingai valdyti visus šiuos etapus. Čia kaip modelį naudoju „SpiderMonkey“.

Gaunasi

Tai nėra parodyta diagramoje, tačiau vienas dalykas, kuris užima laiko, yra tiesiog failo paėmimas iš serverio.

Kadangi „WebAssembly“ yra kompaktiškesnis nei „JavaScript“, jį gauti yra greičiau. Nors sutankinimo algoritmai gali žymiai sumažinti „JavaScript“ paketo dydį, suglaudintas dvejetainis „WebAssembly“ atvaizdavimas vis tiek yra mažesnis.

Tai reiškia, kad jį perkelti tarp serverio ir kliento užtrunka mažiau laiko. Tai ypač pasakytina apie lėtus tinklus.

Analizuojama

Kai jis pasiekia naršyklę, „JavaScript“ šaltinis analizuojamas abstrakčios sintaksės medyje.

Naršyklės dažnai tai daro tingiai, tik analizuodamos tai, ko iš tikrųjų reikia iš pradžių, ir tik sukurdamos dar nepaskambintų funkcijų kamienus.

Iš ten AST yra konvertuojamas į tarpinį vaizdą (vadinamą baitų kodu), kuris būdingas tam JS varikliui.

Priešingai, „WebAssembly“ nereikia atlikti šios transformacijos, nes tai jau yra tarpinis atvaizdavimas. Tiesiog reikia jį iššifruoti ir patvirtinti, kad įsitikintumėte, jog jame nėra klaidų.

Diagrama, kurioje palyginamas dabartinio JS variklio analizavimas su trumpesniu „WebAssembly“ dekodavimu

Kompiliavimas + optimizavimas

Kaip paaiškinau straipsnyje apie JIT, vykdant kodą sudaromas „JavaScript“. Atsižvelgiant į tai, kokie tipai naudojami vykdymo metu, gali tekti sudaryti kelias to paties kodo versijas.

Skirtingos naršyklės skirtingai tvarko „WebAssemble“. Kai kurios naršyklės, prieš pradėdamos vykdyti, sudaro pagrindinį „WebAssembly“ kompiliavimą, o kitos naudoja JIT.

Bet kuriuo atveju „WebAssembly“ prasideda daug arčiau mašinos kodo. Pavyzdžiui, tipai yra programos dalis. Tai vyksta greičiau dėl kelių priežasčių:

  1. Kompiliatorius neprivalo sugaišti laiko vykdydamas kodą, kad galėtų stebėti, kokie tipai naudojami, prieš pradedant kaupti optimizuotą kodą.
  2. Kompiliatorius neprivalo sudaryti skirtingų to paties kodo versijų pagal tuos skirtingus tipus, kuriuos jis stebi.
  3. LLVM jau anksčiau atlikta daugiau optimizacijų. Taigi, norint jį sudaryti ir optimizuoti, reikia mažiau darbo.

Diagrama, palyginanti kompiliavimą + optimizavimą, o „WebAssembly“ yra trumpesnė

Pakartotinis optimizavimas

Kartais JIT turi išmesti optimizuotą kodo versiją ir bandyti ją dar kartą.

Taip nutinka, kai prielaidos, kurias JIT daro remdamasis veikiančiu kodu, pasirodo neteisingos. Pvz., Deoptimizacija įvyksta, kai į kilpą ateinantys kintamieji skiriasi nuo ankstesnių pakartojimų arba kai į prototipų grandinę įterpiama nauja funkcija.

Deoptimizacija yra dvi išlaidos. Pirma, užtrunka šiek tiek laiko, kad būtų galima išgauti optimizuotą kodą ir grįžti į pradinę versiją. Antra, jei ta funkcija vis dar labai dažnai vadinama, JIT gali nuspręsti ją vėl siųsti per optimizavimo kompiliatorių, todėl tenka sumokėti už antrą kartą.

Programoje „WebAssembly“ tokie dalykai, kaip tipai, yra aiškūs, todėl JIT nereikia daryti prielaidų apie tipus pagal duomenis, kuriuos renka vykdymo metu. Tai reiškia, kad jai nereikia pereiti iš naujo optimizavimo ciklų.

Diagrama, rodanti, kad pakartotinis optimizavimas įvyksta JS, tačiau jo nereikia „WebAssembly“

Vykdoma

Galima parašyti „JavaScript“, kuris veikia puikiai. Norėdami tai padaryti, turite žinoti apie optimizavimą, kurį atlieka JIT. Pavyzdžiui, jūs turite žinoti, kaip rašyti kodą, kad kompiliatorius galėtų įvesti tekstą, kaip tai paaiškinta JIT straipsnyje.

Tačiau dauguma kūrėjų nežino apie JIT vidinius elementus. Net tiems kūrėjams, kurie žino apie JIT vidų, gali būti sunku pasiekti gerą vietą. Daugelis kodavimo modelių, kuriuos žmonės naudoja, kad jų kodas būtų lengviau įskaitomas (pvz., Įprastų užduočių suskaidymas į funkcijas, kurios veikia įvairiuose tipuose), trukdo kompiliatoriui, kai jis bando optimizuoti kodą.

Be to, JIT naudojamos optimizacijos skiriasi skirtingose ​​naršyklėse, todėl kodavus vienos naršyklės vidų, jūsų kodas gali būti mažiau efektyvus kitoje.

Dėl to kodas „WebAssembly“ paprastai vykdomas greičiau. Daugelio JIT vykdomų „JavaScript“ optimizavimų (pvz., Tipų specializacijos) tiesiog nereikia naudojant „WebAssembly“.

Be to, „WebAssembly“ buvo sukurtas kaip kompiliatoriaus taikinys. Tai reiškia, kad jis buvo sukurtas kompiliatoriams generuoti, o ne žmonėms programuotojams rašyti.

Kadangi žmogaus programuotojams nereikia to tiesiogiai programuoti, „WebAssembly“ gali pateikti instrukcijų rinkinį, kuris idealiau tinka mašinoms. Atsižvelgiant į tai, kokį darbą dirba jūsų kodas, šios instrukcijos veikia greičiau nei nuo 10% iki 800%.

Diagrama, lyginanti vykdymą, kai „WebAssembly“ yra trumpesnė

Šiukšlių kolekcija

„JavaScript“ programuotojui nereikia rūpintis išvalyti senus kintamuosius iš atminties, kai jų nebereikia. Vietoj to, JS variklis tai daro automatiškai naudodamas tai, kas vadinama šiukšlių surinkėju.

Vis dėlto tai gali būti problema, jei norite nuspėjamo našumo. Jūs nekontroliuojate, kada šiukšlių surinkėjas atlieka savo darbą, todėl tai gali ateiti nepatogiu metu. Daugeliui naršyklių sekėsi planuoti, tačiau vis tiek tai gali trukdyti jūsų kodui vykdyti.

Bent jau kol kas „WebAssembly“ visiškai nepalaiko šiukšlių rinkimo. Atmintis tvarkoma rankiniu būdu (kaip ir tokiomis kalbomis kaip C ir C ++). Nors tai gali apsunkinti kūrėjo programavimą, jis taip pat daro nuoseklesnį našumą.

Diagrama, rodanti, kad šiukšlių surinkimas vyksta JS, tačiau to nereikia „WebAssembly“

Išvada

Daugeliu atvejų žiniatinklio surinkimas yra greitesnis nei „JavaScript“, nes:

  • „WebAssembly“ atėmimas užtrunka mažiau laiko, nes jis yra kompaktiškesnis nei „JavaScript“, net ir suspaustas.
  • „WebAssembly“ dekodavimas užtrunka mažiau laiko nei „JavaScript“ analizavimas.
  • kompiliavimas ir optimizavimas užtrunka mažiau laiko, nes „WebAssembly“ yra arčiau mašinos kodo nei „JavaScript“ ir jau yra optimizuotas serverio pusėje.
  • optimizuoti nereikia, nes „WebAssembly“ turi tipų ir kitos informacijos, todėl JS varikliui nereikia spėlioti, kai jis optimizuoja tai, ką daro su „JavaScript“.
  • vykdymas dažnai užtrunka mažiau laiko, nes yra mažiau kompiliatorių gudrybių ir gudrybių, kurias kūrėjas turi žinoti, norėdamas nuolat rašyti efektyvų kodą, be to, „WebAssembly“ instrukcijų rinkinys yra idealesnis mašinoms.
  • šiukšlių rinkimas nereikalingas, nes atmintis tvarkoma rankiniu būdu.

Štai kodėl daugeliu atvejų „WebAssembly“, atlikdamas tą pačią užduotį, pranoks „JavaScript“.

Kai kuriais atvejais „WebAssembly“ veikia ne taip gerai, kaip tikėtasi, taip pat horizonte yra keletas pakeitimų, kurie padarys jį greitesnį. Aš juos aptarsiu kitame straipsnyje.

Linas dirba „Mozilla“ programoje „Advanced Development“, daugiausia dėmesio skiriant „Rust“ ir „WebAssembly“.

Daugiau Lino Clarko straipsnių …

Parašykite komentarą

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *

Previous post Paaiškino: koks yra deguonies krizės Indijoje mastas ir kokie yra jų sprendimo būdai
Next post Štai ką jis gali padaryti