
В тази статия разглеждаме случай на ускоряване на браузерно приложение, заменяйки JavaScript изчисленията с WebAssembly.
WebAssembly — какво е това?
С две думи, това е бинарен формат на инструкции за стекова виртуална машина. Често Wasm (съкратеното наименование) се нарича програмен език, но това не е точно така. Форматът на инструкциите се изпълнява в браузъра заедно с JavaScript.
Важно е, че WebAssembly може да бъде получен при компилиране на код на езици като C/C++, Rust, Go. Тук се използва статична типизация и така нареченият плосък модел на паметта. Кодът, както беше споменато, се съхранява в компактен бинарен формат, благодарение на което изпълнението е почти толкова бързо, колкото ако приложението беше стартирано чрез команден ред. Тези възможности доведоха до растежа на популярността на WebAssembly.
Напомняме: за всички читатели на «Хабра» — отстъпка от 10 000 рубли при записване на всеки курс Skillbox с промокод «Хабр».
Skillbox препоръчва: Практически курс .
В момента Wasm се използва в много приложения, от игри като Doom 3 до портировани уеб приложения като Autocad и Figma. Wasm се прилага и в областта на безсървърни изчисления.
В тази статия е представен пример за използване на Wasm за ускоряване на аналитичен уеб сервис. За конкретност взехме работещо приложение, написано на C, което ще бъде компилирано в WebAssembly. Резултатът ще бъде използван за замяна на малко ефективни участъци от JS.
Трансформация на приложението
В примера ще бъде използвана браузерната услуга fastq.bio, която е предназначена за генетици. Инструментът позволява оценка на качеството на секвенирането (декодирането) на ДНК.
Ето пример на приложението в действие:

Подробностите на процеса не е необходимо да бъдат посочвани, тъй като те са доста сложни за неспециалисти, но в кратце, учените чрез посочената по-горе инфографика могат да разберат дали процесът на секвениране на ДНК е преминал гладко и какви проблеми са възникнали.
Тази услуга има алтернативи, десктоп програми. Но fastq.bio позволява ускоряване на работата, визуализирайки данните. В повечето други случаи е необходимо да се работи с команден ред, но не на всички генетици имат нужния опит.
Всичко работи просто. На входа — данни, представени във вид на текстов файл. Този файл се генерира с помощта на специализирани инструменти за секвениране. В него се помещава списък на последователностите на ДНК и оценка на качеството за всеки нуклеотид. Форматът на файла е .fastq, поради което услугата и е получила това название.
Имплементация на JavaScript
Първата стъпка на потребителя при работа с fastq.bio е изборът на подходящ файл. Използвайки обект File, приложението прочита случайна извадка от данни от файла и обработва този пакет. Задачата на JavaScript тук е да извърши несложни стрингови операции и да изчисли показатели. Един от тях е броят на нуклеотидите A, C, G и T в различни фрагменти на ДНК.
След изчислението на необходимите показатели те се визуализират с помощта на Plotly.js, а услугата започва работа с нова извадка данни. Разделянето на фрагменти е направено за повишаване на качеството на UX. Ако се работи с всички данни наведнъж, процесът ще се забави за известно време, тъй като файловете с резултатите от секвенирането заемат стотици гигабайти файлово пространство. Услугата взема участъци от данни с размер от 0,5 до 1 Мб и работи с тях стъпка по стъпка, изграждайки графични данни.
Ето как работи:

В червения правоъгълник се намира алгоритъмът за стрингови преобразувания за получаване на визуализация. Това е най-интензивната по изчисления част на услугата. Струва си да пробвате да я замените с Wasm.
Тест на WebAssembly
За оценка на възможността за използване на Wasm, екипът на проекта се зае с търсене на готови решения за създаване на QC-метрика (QC — контрол на качеството) на базата на файлове fastq. Проучването бе проведено сред инструменти, написани на C, C++ или Rust, за да има възможност за портване на кода в WebAssembly. Освен това, инструментът не трябва да бъде „суров“, необходим е сервис, вече проверен от учени.
В резултат на това изборът беше направен в полза на . Приложението е доста популярно, то е с отворен код, основният език е C.
Преди преобразуването в Wasm, струва си да се види принципът на компилация на seqtk за десктоп. Според Makefile, ето какво е необходимо:
# Compile to binary
$ gcc seqtk.c
-o seqtk
-O2
-lm
-lzВ принцип, seqtk може да бъде компилиран с помощта на Emscripten. Ако го нямате, можем да използваме .
$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26При желание , но за това е нужно време.
В контейнера без проблем можете използвате emcc като алтернатива на gcc:
# Compile to WebAssembly
$ emcc seqtk.c
-o seqtk.js
-O2
-lm
-s USE_ZLIB=1
-s FORCE_FILESYSTEM=1Минимални изменения:
Вместо извеждането в бинарен файл, Emscripten генерира .wasm и .js файлове, които се използват за стартиране на модула WebAssembly.
За поддръжка на библиотеката zlib е активиран флагът USE_ZLIB. Библиотеката е широко разпространена и портируема на WebAssembly, а Emscripten я включва в проекта.
Активира се виртуалната файлова система на Emscripten. Това , която работи в оперативната памет на браузера. Когато страницата се обновява, паметта се изчиства.
За да разберем защо е нужна виртуалната файлова система, си струва да сравним как се стартира seqtk от командния ред със старта на компилирания модул WebAssembly.
# On the command line
$ ./seqtk fqchk data.fastq
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])Достъпът до виртуалната файлова система е необходим, за да не се пренаписва seqtk за стрингов, а не файлов вход. В този случай фрагментът данни се показва като файл data.fastq във виртуалната файлова система с основен извикване на main() seqtk.
Ето новата архитектура:

Графиката показва, че вместо изчисления в основния поток на браузера се използва . Този метод позволява да се извършват изчисления на фоновия поток, без да се влошава отзивчивостта на браузера. А контролерът на WebWorker стартира Worker, управлявайки взаимодействието му с основния поток.
Командата seqtk се стартира с помощта на Worker на монтирания файл. След завършване на Worker, резултатът се издава под формата на Promise. Когато съобщението бъде получено от основния поток, резултатът се използва за актуализиране на графиците. И така в няколко итерации.
Какво да кажем за производителността на WebAssembly?
За да оценят промяната в производителността, екипът на проекта е използвал параметъра за брой операции за четене в секунда. Времето за построяване на интерактивни графици не се взима предвид, тъй като в двете имплементации се използва JavaScript.
При използване на "извън кутията" производителността е нараснала девет пъти.

Това е отличен резултат, но, както се оказва, има възможност за оптимизация и него. Работата е там, че много от резултатите от QC анализа не се използват от seqtk, така че могат да бъдат премахнати. Ако това бъде направено, резултатът в сравнение с JS се подобрява 13 пъти.

Успяха да го постигнат само с коментиране на командите printf().
Но и това не е всичко. Факт е, че на този етап fastq.bio получава резултати от анализа с извикване на различни функции на C. Всяка от тях изчислява своят набор от характеристики, така че всеки фрагмент от файла беше прочетен два пъти.
За да се справим с този проблем, беше взето решение да се комбинират две функции в една. В резултат производителността нарасна 20 пъти.

Важно е да се отбележи, че такъв впечатляващ резултат не може да бъде постигнат винаги. В някои случаи производителността спада, така че е необходимо да се оценява всеки конкретен случай.
Като заключение, може да се каже, че Wasm наистина предоставя възможност за подобряване на производителността на приложението, но трябва да се използва разумно.
Skillbox препоръчва:
- Двугодишен практически курс .
- Онлайн курс .
- Практически годишен курс .
Източник: habr.com
