
В тази статия се разглежда случай за ускоряване на браузърно приложение чрез замяна на изчисленията с JavaScript с WebAssembly.
Какво е WebAssembly?
Накратко, това е бинарен формат на инструкции за стекова виртуална машина. Често Wasm (съкратено название) се нарича програмен език, но това не е вярно. Форматът на инструкциите се изпълнява в браузъра заедно с JavaScript.
Важно е, че WebAssembly може да бъде получен при компилиране на изходен код на такива езици като C/C++, Rust, Go. Тук се прилага статична типизация и т. нар. плоска модел на паметта. Кодът, както беше споменато, се съхранява в компактния бинарен формат, благодарение на което се изпълнява почти толкова бързо, колкото ако приложението беше стартирано чрез команден ред. Тези възможности доведоха до нарастваща популярност на WebAssembly.
Напомняме: за всички читатели на "Хабра" — отстъпка от 10 000 рубли при записване на всякакъв курс на Skillbox с промокод "Хабр".
Skillbox препоръчва: Практически курс .
В момента Wasm се използва в много приложения, от игри като Doom 3 до портировани уеб приложения като Autocad и Figma. Wasm се прилага и в такава сфера, като serverless изчисления.
В тази статия е представен пример за използване на 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 – quality control) на базата на файлове fastq. Търсенето се проведе сред инструменти, написани на C, C++ или Rust, за да има възможност за портване на кода на WebAssembly. Освен това инструментът не трябва да е "суров", изискваше се услуга, вече проверена от учени.
В резултат на това изборът беше направен в полза на . Приложението е доста популярно, то е open-source, изходният език е 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 и затова могат да бъдат премахнати. Ако направим това, резултатът в сравнение с JavaScript се подобрява 13 пъти.

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

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