
Acest articol analizează un caz de accelerare a aplicației de browser prin înlocuirea calculilor JavaScript cu WebAssembly.
Ce este WebAssembly?
Pe scurt, este un format binar de instrucțiuni pentru o mașină virtuală pe stivă. De multe ori, Wasm (numele prescurtat) este denumit limbaj de programare, dar acest lucru nu este corect. Formatul instrucțiunilor este executat în browser împreună cu JavaScript.
Este important de menționat că WebAssembly poate fi obținut prin compilarea surselor în limbaje precum C/C++, Rust, Go. Aici se aplică tipizarea statică și modelul de memorie aplatizat. Codul, așa cum s-a menționat mai sus, este stocat într-un format binar compact, ceea ce face ca executarea să fie aproape la fel de rapidă ca și cum aplicația ar fi fost rulată folosind linia de comandă. Aceste capacități au dus la creșterea popularității WebAssembly.
Vă reamintim: pentru toți cititorii „Habr” — reducere de 10.000 de ruble la înscrierea la orice curs Skillbox cu codul de promovare „Habr”.
Skillbox recomandă: Curs practic .
În prezent, Wasm este utilizat în numeroase aplicații, de la jocuri precum Doom 3 până la aplicații portate în web, cum ar fi Autocad și Figma. Wasm este folosit și în domeniul calculilor serverless.
Acest articol oferă un exemplu de utilizare a Wasm pentru accelerarea unui serviciu web analitic. Pentru claritate, am folosit o aplicație funcțională, scrisă în C, care va fi compilată în WebAssembly. Rezultatul va fi folosit pentru a înlocui porțiunile de JS cu performanțe reduse.
Transformarea aplicației
În exemplu, va fi utilizat serviciul web fastq.bio, destinat geneticii. Instrumentul permite evaluarea calității secvențierii (decodificării) ADN-ului.
Iată un exemplu de aplicație în acțiune:

Detaliile procesului nu trebuie descrise, deoarece sunt destul de complexe pentru ne-specialiști, dar, pe scurt, cercetătorii, conform infograficei menționate mai sus, pot înțelege dacă procesul de secvențiere a ADN-ului a decurs fără probleme și ce probleme au apărut.
Acest serviciu are alternative, programe desktop. Dar fastq.bio permite accelerarea lucrărilor prin vizualizarea datelor. În majoritatea celorlalte cazuri, este nevoie de experiență cu linia de comandă, dar nu toți geneticii au expertiza necesară.
Totul funcționează simplu. La intrare sunt datele prezentate sub formă de fișier text. Acest fișier este generat de instrumente specializate pentru secvențiere. În fișier se află o listă de secvențe ADN și evaluarea calității pentru fiecare nucleotide. Formatul fișierului este .fastq, de aceea serviciul a primit acest nume.
Implementare în JavaScript
Primul pas al utilizatorului la lucrul cu fastq.bio este alegerea fișierului corespunzător. Folosind obiectul File, aplicația citește o mostră aleatorie de date din fișier și prelucrează acest lot. Sarcina JavaScript aici este să efectueze operații simple pe șiruri și să calculeze indicatorii. Unul dintre aceștia este numărul nucleotidelor A, C, G și T în diferite fragmente de ADN.
După calcularea indicatorilor necesari, aceștia sunt vizualizați cu ajutorul Plotly.js, iar serviciul începe să lucreze cu o nouă mostră de date. Fragmentarea este realizată pentru a îmbunătăți calitatea UX. Dacă se lucrează cu toate datele simultan, procesul va bloca timp de un moment, deoarece fișierele cu rezultatele secvențierii ocupă sute de gigaocteți de spațiu pe disc. Serviciul preia secțiuni de date cu dimensiuni cuprinse între 0,5 și 1 MB și lucrează cu ele pas cu pas, construind datele grafice.
Iată cum funcționează:

În dreptunghiul roșu se află algoritmul de transformare a șirurilor pentru a obține vizualizarea. Aceasta este cea mai intensă parte din punct de vedere al calculului a serviciului. Merită să încercați să o înlocuiți cu Wasm.
Testăm WebAssembly
Pentru a evalua posibilitatea utilizării Wasm, echipa proiectului s-a ocupat de căutarea unor soluții gata făcute pentru crearea metricii QC (QC - controlul calității) pe baza fișierelor fastq. Căutarea a fost realizată printre instrumentele scrise în C, C++ sau Rust, pentru a avea posibilitatea de a porta codul în WebAssembly. În plus, instrumentul nu trebuie să fie "brut", fiind necesar un serviciu care a fost deja validat de cercetători.
Ca rezultat, alegerea a fost făcută în favoarea . Aplicația este destul de populară, este open-source, iar limbajul sursă este C.
Înainte de a transforma în Wasm, merită să se examineze principiul de compilare al seqtk pentru desktop. Conform Makefile, iată ce este necesar:
# Compile to binary
$ gcc seqtk.c
-o seqtk
-O2
-lm
-lzÎn principiu, seqtk poate fi compilat cu ajutorul Emscripten. Dacă nu este disponibil, ne descurcăm .
$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26Dacă doriți, , dar acest lucru va necesita timp.
În interiorul containerului, poți folosi cu încredere emcc ca alternativă la gcc:
# Compile to WebAssembly
$ emcc seqtk.c
-o seqtk.js
-O2
-lm
-s USE_ZLIB=1
-s FORCE_FILESYSTEM=1Minimele schimbări:
În loc de a genera un fișier binar, Emscripten utilizează .wasm și .js pentru a crea fișiere, care sunt folosite pentru a rula modulul WebAssembly.
Pentru a susține biblioteca zlib, se utilizează flagul USE_ZLIB. Această bibliotecă este răspândită și portată pe WebAssembly, iar Emscripten o include în proiect.
Se activează sistemul de fișiere virtual Emscripten. Acesta , care funcționează în memoria RAM din browser. Când pagina este reîncărcată, memoria este ștearsă.
Pentru a înțelege de ce este necesar un sistem de fișiere virtual, este bine să compari modul de a rula seqtk din linia de comandă cu modul de a rula modulul compilat WebAssembly.
# On the command line
$ ./seqtk fqchk data.fastq
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])Accesul la sistemul de fișiere virtual este necesar pentru a nu rescrie seqtk pentru intrare de tip string și nu pentru fișiere. În acest caz, fragmentul de date este mapat ca fișier data.fastq în FS-ul virtual, cu apelul main() seqtk.
Iată noua arhitectură:

Ilustrația demonstrează că, în loc de calcule în firul principal al browserului, se folosește . Această metodă permite executarea calculelor în firul de fundal, fără a afecta reacția browserului. Iar controlerul WebWorker inițiază Worker-ul, gestionând interacțiunea sa cu firul principal.
Comanda seqtk este apelată prin intermediul Worker-ului pe fișierul montat. După finalizarea execuției, Worker-ul returnează rezultatul sub formă de Promise. Când mesajul este primit de firul principal, rezultatul este folosit pentru a actualiza graficele. Și așa în câteva iterații.
Ce părere ai despre performanța WebAssembly?
Pentru a evalua schimbarea performanței, echipa proiectului a utilizat parametrul de număr de operații de citire pe secundă. Timpul de construire a graficelor interactive nu este inclus, deoarece în ambele implementări se folosește JavaScript.
Folosind soluția „din cutie”, creșterea performanței a fost de nouă ori.

Acesta este un rezultat excelent, dar, așa cum s-a constatat, există posibilitatea de a-l optimiza și mai mult. Problema este că un număr mare de rezultate QC-analiză nu sunt utilizate de seqtk, așa că pot fi eliminate. Dacă se face acest lucru, rezultatul comparativ cu JS se îmbunătățește de 13 ori.

Acest lucru a fost realizat simplu prin comentarea comenzilor printf().
Dar aceasta nu este tot. La acest stadiu, fastq.bio primește rezultatele analizei prin apelarea diferitelor funcții C. Fiecare dintre ele calculează propriul set de caracteristici, astfel încât fiecare fragment de fișier a fost citit de două ori.
Pentru a rezolva această problemă, s-a decis combinarea a două funcții într-una singură. Ca rezultat, performanța a crescut de 20 de ori.

Este important de menționat că un astfel de rezultat remarcabil nu poate fi atins întotdeauna. În unele cazuri, performanța scade, așa că trebuie evaluat fiecare caz în parte.
În concluzie, se poate spune că Wasm oferă cu adevărat oportunitatea de a îmbunătăți performanța aplicației, dar trebuie folosit cu înțelepciune.
Skillbox recomandă:
- Curs practic de doi ani .
- Curs online .
- Curs practic anual .
Sursa: habr.com
