WebAssembly: C++ kodas naršyklėje

Kas ta WebAssembly ir kodėl ji tokia svarbi?

Prisimenu, kai pirmą kartą išgirdau apie WebAssembly – maniau, kad tai dar vienas iš tų hype technologijų, kurios ateis ir greitai išnyks. Bet buvau neteisus. WebAssembly (arba WASM, kaip ją mėgsta trumpinti programuotojai) iš tikrųjų keičia žaidimo taisykles interneto programavime.

Paprasčiausiai tariant, WebAssembly leidžia paleisti beveik natyvaus greičio kodą tiesiog naršyklėje. Taip, teisingai supratote – galite paimti C++, Rust ar kitą kompiliuojamą kalbą, paversti ją WASM formatu ir paleisti Chrome, Firefox ar bet kurioje kitoje šiuolaikinėje naršyklėje. Tai tarsi turėtumėte superkompiuterį tiesiog savo naršyklės lange.

Kodėl tai svarbu? Na, JavaScript yra puikus, bet kai reikia atlikti sunkius skaičiavimus, apdoroti vaizdo įrašus, paleisti žaidimus su sudėtinga grafika ar dirbti su dirbtinio intelekto modeliais – JavaScript tiesiog nepakanka. WebAssembly užpildo šią spragą, leisdama mums naudoti jau egzistuojančias C++ bibliotekas ir kodą tiesiog internete.

Kaip C++ kodas atsiduria naršyklėje?

Procesas nėra toks sudėtingas, kaip galite pagalvoti. Pagrindinis įrankis čia yra Emscripten – kompiliatorius, kuris paverčia C++ kodą į WebAssembly. Tai tarsi tiltas tarp tradicinio programavimo pasaulio ir interneto.

Štai kaip tai veikia praktiškai. Turite paprastą C++ funkciją:

„`cpp
#include

extern „C” {
EMSCRIPTEN_KEEPALIVE
int fibonacci(int n) {
if (n <= 1) return n; return fibonacci(n-1) + fibonacci(n-2); } } ``` Kompiliuojate ją su Emscripten: ``` emcc fibonacci.cpp -o fibonacci.js -s EXPORTED_FUNCTIONS='["_fibonacci"]' -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]' ``` Ir voila – gausite du failus: `.wasm` failą su kompiliuotu kodu ir `.js` failą, kuris padeda jį įkelti ir naudoti. JavaScript pusėje galite tiesiog iškviesti šią funkciją tarsi ji būtų įprasta JavaScript funkcija. Emscripten daro daug daugiau nei tik kompiliuoja kodą. Jis automatiškai sukuria visą reikiamą infrastruktūrą, kad jūsų C++ kodas galėtų bendrauti su JavaScript, valdyti atmintį ir net naudoti standartines C++ bibliotekas.

Realūs panaudojimo atvejai, kurie įkvepia

Teorija yra gera, bet kas iš tikrųjų naudoja WebAssembly produkcijoje? Atsakymas – labai daug kas, ir kai kurie pavyzdžiai tikrai įspūdingi.

**Figma** – populiarus dizaino įrankis – perkėlė savo renderinimo variklį į C++ su WebAssembly ir pasiekė 3x greitesnį veikimą. Tai ne mažas pagerinimas, tai fundamentalus skirtumas tarp lėtos ir sklandžios patirties.

**Google Earth** dabar veikia naršyklėje be jokių papildomų įskiepių, naudodamas WebAssembly. Anksčiau tam reikėjo Native Client ar kitų specifinių technologijų. Dabar tiesiog atidarote naršyklę ir keliaujate po pasaulį.

**AutoCAD** – taip, tas pats AutoCAD, kuris dešimtmečius buvo desktop aplikacija – dabar veikia naršyklėje. Tai milžiniškas projektas su milijonais kodo eilučių, ir WebAssembly padarė tai įmanoma.

Vaizdo ir garso kodavimas taip pat yra puiki sritis WebAssembly. FFmpeg biblioteka, kompiliuota į WASM, leidžia konvertuoti vaizdo įrašus tiesiog naršyklėje, nesiųsdami jų į serverį. Tai ne tik greitesnis, bet ir saugesnis sprendimas.

Našumo palyginimas: skaičiai nemelsuoja

Kalbant apie našumą, WebAssembly tikrai įspūdinga. Tipiškai WASM kodas veikia maždaug 1.5-2x lėčiau nei natyvus C++ kodas, bet 10-20x greičiau nei optimizuotas JavaScript.

Dariau savo testus su vaizdų apdorojimu – paprastu blur filtru 1920×1080 paveikslėliui. JavaScript užtruko apie 450ms, o WebAssembly versija – vos 35ms. Tai ne teorinis skirtumas, tai juntamas našumo šuolis.

Bet čia yra niuansų. Ne viskas, kas veikia greitai C++, automatiškai veiks greitai WASM. Dažni šaukimai tarp JavaScript ir WebAssembly gali būti lėti. Duomenų kopijavimas iš JavaScript į WASM atmintį ir atgal taip pat kainuoja. Todėl geriausias našumas pasiekiamas, kai didžioji dalis skaičiavimų vyksta WASM pusėje, o komunikacija su JavaScript yra minimali.

Atminties valdymas ir duomenų mainai

Viena iš sudėtingiausių dalių dirbant su WebAssembly yra atminties valdymas. WASM naudoja liniją atminties modelį – tai iš esmės didelis masyvų baitas, kurį dalijasi JavaScript ir WebAssembly kodas.

Kai perduodate duomenis iš JavaScript į C++, dažniausiai reikia juos nukopijuoti į šią bendrą atmintį. Štai tipiškas pavyzdys:

„`javascript
const data = new Float32Array([1.0, 2.0, 3.0, 4.0]);
const ptr = Module._malloc(data.length * data.BYTES_PER_ELEMENT);
Module.HEAPF32.set(data, ptr >> 2);
Module._processData(ptr, data.length);
Module._free(ptr);
„`

Taip, reikia rankiniu būdu valdyti atmintį su `malloc` ir `free`. Tai gali atrodyti archajiška JavaScript programuotojui, bet tai būtina, kad C++ kodas galėtų efektyviai dirbti su duomenimis.

Naujesni įrankiai ir bibliotekos, kaip Embind, padeda supaprastinti šį procesą, automatiškai tvarkydami daug atminties valdymo detalių. Bet vis tiek svarbu suprasti, kas vyksta po gaubtu.

Threading ir paralelizavimas

Viena iš galingiausių WebAssembly funkcijų yra galimybė naudoti kelis gijas (threads). Tai leidžia išnaudoti daugiabrandžinius procesorius ir dar labiau padidinti našumą.

Tačiau čia yra keletas keblumo. Pirmiausia, jūsų serveris turi siųsti specialius HTTP headerius (`Cross-Origin-Opener-Policy` ir `Cross-Origin-Embedder-Policy`), kad įgalintų SharedArrayBuffer, kuris reikalingas threading’ui.

Antra, ne visi naršyklių kontekstai palaiko threading’ą. Pavyzdžiui, kai kuriuose mobiliuose naršyklėse palaikymas gali būti ribotas.

Bet kai tai veikia, rezultatai gali būti fantastiniai. Turėjau projektą, kur apdorojau didelius duomenų rinkinius – su 4 gijomis pasiekiau beveik 3.5x greitesnį veikimą nei su viena gija. Tai ne tiesinis pagerinimas, bet vis tiek labai įspūdinga.

Integracija su JavaScript ekosistema

Vienas iš dažniausių klausimų – kaip WebAssembly bendrauja su JavaScript bibliotekomis ir framework’ais? Atsakymas: gana gerai, bet reikia šiek tiek darbo.

Galite iškviesti JavaScript funkcijas iš C++ kodo naudodami Emscripten API:

„`cpp
#include

EM_JS(void, call_alert, (), {
alert(‘Hello from C++!’);
});

void myFunction() {
call_alert();
}
„`

Atvirkščiai, galite eksportuoti C++ funkcijas ir jas kviesti iš JavaScript. Embind biblioteka daro tai dar paprasčiau, leisdama eksportuoti net sudėtingas klases:

„`cpp
#include

class MyClass {
public:
MyClass(int x) : value(x) {}
int getValue() { return value; }
void setValue(int x) { value = x; }
private:
int value;
};

EMSCRIPTEN_BINDINGS(my_module) {
emscripten::class_(„MyClass”)
.constructor()
.function(„getValue”, &MyClass::getValue)
.function(„setValue”, &MyClass::setValue);
}
„`

JavaScript pusėje tai atrodo visiškai natūraliai:

„`javascript
const obj = new Module.MyClass(42);
console.log(obj.getValue()); // 42
obj.setValue(100);
„`

Ką reikia žinoti prieš pradedant projektą

WebAssembly nėra sidabrinė kulka. Yra situacijų, kai ji puikiai tinka, ir situacijų, kai geriau pasilikti su JavaScript.

**Kada naudoti WebAssembly:**
– Sunkūs skaičiavimai (kriptografija, simuliacijos, moksliniai skaičiavimai)
– Vaizdo/garso/video apdorojimas
– Žaidimai su sudėtinga logika
– Egzistuojančio C/C++ kodo perkėlimas į internetą
– Kai našumas yra kritinis

**Kada NENAUDOTI WebAssembly:**
– Paprastoms CRUD operacijoms
– Kai daugiausia dirbi su DOM
– Mažiems projektams, kur JavaScript našumo užtenka
– Kai komandoje niekas nežino C++ ar Rust

Failų dydis taip pat svarbus. WASM failai gali būti dideli – net paprastas C++ kodas su standartine biblioteka gali užimti kelis megabaitus. Nors gzip kompresija labai padeda, vis tiek reikia apgalvoti įkėlimo laiką.

Debugging’as taip pat sudėtingesnis. Nors šiuolaikinės naršyklės palaiko WASM debugging’ą su source maps, tai vis tiek ne taip patogu kaip debug’inti JavaScript.

Ateities perspektyvos ir ką turime dabar

WebAssembly technologija sparčiai vystosi. WASI (WebAssembly System Interface) žada paleisti WASM kodą ne tik naršyklėse, bet ir serveriuose, IoT įrenginiuose, visur. Tai galėtų tapti universalia kompiliavimo platforma.

Garbage Collection palaikymas, kuris jau kuriamas, leis efektyviau naudoti kalbas kaip Java, C#, Go. Component Model standartizuos, kaip skirtingi WASM moduliai bendrauja tarpusavyje.

Bet net dabar, su tuo ką turime, WebAssembly jau yra pakankamai brandi technologija produkciniams projektams. Didžiosios kompanijos ja naudojasi, įrankiai yra stabilūs, dokumentacija gera.

Jei jūsų projektas reikalauja našumo, jei turite egzistuojantį C++ kodą, kurį norite panaudoti internete, arba jei tiesiog norite išmokti kažką naujo ir perspektyvaus – WebAssembly yra puikus pasirinkimas. Taip, mokymosi kreivė yra statesne nei įprasto web development, bet rezultatai to verti.

Pradėkite nuo mažų eksperimentų. Pabandykite sukompiliuoti paprastą C++ funkciją, paleiskite ją naršyklėje, pamatuokite našumą. Palaipsniui suprasite, kur WASM gali padėti jūsų projektuose, o kur geriau pasilikti su JavaScript. Ir kas žino – galbūt jūsų kitas projektas bus tas, kuris nustebins pasaulį tuo, ką galima padaryti tiesiog naršyklėje.

Daugiau

Ant Design React UI biblioteka