Como usamos WebAssembly para acelerar unha aplicación web 20 veces
Este artigo analiza un caso para acelerar unha aplicación de navegador substituíndo os cálculos de JavaScript por WebAssembly.
WebAssembly - que é?
En resumo, este é un formato de instrucións binarias para unha máquina virtual baseada en pilas. Wasm (nome abreviado) adoita chamarse linguaxe de programación, pero non o é. O formato de instrución execútase no navegador xunto con JavaScript.
É importante que WebAssembly se poida obter compilando fontes en linguaxes como C/C++, Rust, Go. Aquí utilízase a tipificación estatística e o chamado modelo de memoria plana. O código, como se mencionou anteriormente, almacénase nun formato binario compacto, o que o fai case tan rápido como executar a aplicación mediante a liña de comandos. Estas capacidades levaron ao crecemento da popularidade de WebAssembly.
Recordámolo:para todos os lectores de "Habr" - un desconto de 10 rublos ao inscribirse en calquera curso de Skillbox usando o código promocional "Habr".
Actualmente, Wasm utilízase en moitas aplicacións, desde xogos como Doom 3 ata aplicacións portadas na web como Autocad e Figma. Wasm tamén se usa en áreas como a informática sen servidor.
Este artigo ofrece un exemplo de uso de Wasm para acelerar un servizo web de análise. Para máis claridade, tomamos unha aplicación de traballo escrita en C, que está compilada en WebAssembly. O resultado empregarase para substituír seccións de JS con baixo rendemento.
Transformación de aplicacións
O exemplo usará o servizo de navegador fastq.bio, destinado a xenetistas. A ferramenta permite avaliar a calidade da secuenciación do ADN (descifrado).
Aquí tes un exemplo da aplicación en acción:
Non paga a pena entrar nos detalles do proceso xa que son bastante complexos para os non especialistas, pero en resumo, os científicos poden utilizar a infografía anterior para comprender se o proceso de secuenciación do ADN foi ben e que problemas xurdiron.
Este servizo ten alternativas, programas de escritorio. Pero fastq.bio permíteche acelerar o teu traballo visualizando os datos. Na maioría dos outros casos, debes poder traballar coa liña de comandos, pero non todos os xenetistas teñen a experiencia necesaria.
Todo funciona simplemente. A entrada son datos presentados en forma de ficheiro de texto. Este ficheiro é xerado por ferramentas de secuenciación especializadas. O ficheiro contén unha lista de secuencias de ADN e unha puntuación de calidade para cada nucleótido. O formato de ficheiro é .fastq, polo que o servizo recibiu o seu nome.
Implementación en JavaScript
O primeiro paso do usuario cando traballa con fastq.bio é seleccionar o ficheiro axeitado. Usando o obxecto Ficheiro, a aplicación le unha mostra aleatoria de datos dun ficheiro e procesa ese lote. O traballo de JavaScript aquí é realizar operacións sinxelas de cadeas e calcular métricas. Un deles é o número de nucleótidos A, C, G e T en diferentes fragmentos de ADN.
Despois de calcular os indicadores necesarios, visualízanse mediante Plotly.js e o servizo comeza a funcionar cunha nova mostra de datos. A fragmentación realízase para mellorar a calidade da UX. Se traballas con todos os datos á vez, o proceso conxelarase durante algún tempo, xa que os ficheiros cos resultados da secuencia ocupan centos de gigabytes de espazo. O servizo toma datos de 0,5 a 1 MB e traballa con eles paso a paso creando datos gráficos.
Así funciona:
O rectángulo vermello contén o algoritmo de transformación de cadeas para obter a visualización. Esta é a parte máis computacional do servizo. Paga a pena tentar substituílo por Wasm.
Probando WebAssembly
Para avaliar a posibilidade de usar Wasm, o equipo do proxecto comezou a buscar solucións preparadas para crear métricas de QC (QC - control de calidade) baseadas en ficheiros fastq. A busca realizouse entre ferramentas escritas en C, C++ ou Rust, de xeito que foi posible portar o código a WebAssembly. Ademais, a ferramenta non debería ser "en bruto" requiríase un servizo que xa fora probado polos científicos.
Como resultado, a elección foi a favor de seqtk. A aplicación é bastante popular, é de código aberto, a linguaxe fonte é C.
Antes de converterse a Wasm, paga a pena mirar o principio de compilación de seqtk para o escritorio. Segundo o Makefile, aquí tes o que necesitas:
En lugar de emitir un ficheiro binario, Emscripten usa .wasm e .js para xerar os ficheiros, que se usan para executar o módulo WebAssemby.
A marca USE_ZLIB úsase para admitir a biblioteca zlib. A biblioteca foi distribuída e portada a WebAssembly, e Emscripten inclúea no proxecto.
O sistema de ficheiros virtual Emscriptpten está activado. Isto FS tipo POSIX, executándose en RAM dentro do navegador. Cando se actualiza a páxina, a memoria bótase.
Para entender por que se necesita un sistema de ficheiros virtual, paga a pena comparar a forma en que executa seqtk desde a liña de comandos coa forma en que executa un módulo WebAssembly compilado.
# On the command line
$ ./seqtk fqchk data.fastq
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])
É necesario acceder ao sistema de ficheiros virtual para non reescribir seqtk para a cadea en lugar da entrada do ficheiro. Neste caso, o fragmento de datos móstrase como un ficheiro data.fastq no FS virtual cunha chamada a main() seqtk nel.
Aquí está a nova arquitectura:
A figura mostra que en lugar dos cálculos no fío principal do navegador, WebWorkers. Este método permítelle realizar cálculos nun fío en segundo plano sen afectar á capacidade de resposta do navegador. Ben, o controlador WebWorker inicia o Worker, xestionando a súa interacción co fío principal.
O comando seqtk execútase usando Worker no ficheiro montado. Despois de completar a execución, o traballador produce un resultado en forma de promesa. Cando o fío principal recibe unha mensaxe, o resultado utilízase para actualizar os gráficos. E así sucesivamente en varias iteracións.
E o rendemento de WebAssembly?
Para avaliar o cambio no rendemento, o equipo do proxecto utilizou o parámetro de operacións de lectura por segundo. Non se ten en conta o tempo que leva construír gráficos interactivos xa que ambas as implementacións usan JavaScript.
Ao usar a solución lista para usar, o aumento do rendemento foi de nove veces.
Este é un excelente resultado, pero, como se ve, tamén hai unha oportunidade de optimizalo. O feito é que seqtk non usa un gran número de resultados da análise de control de calidade, polo que se poden eliminar. Se fai isto, o resultado mellora 13 veces en comparación con JS.
Conseguiuse simplemente comentando os comandos printf().
Pero iso non é todo. O caso é que nesta fase, fastq.bio recibe os resultados da análise chamando a diferentes funcións C Cada unha delas calcula o seu propio conxunto de características, de xeito que cada fragmento do ficheiro se le dúas veces.
Para evitar este problema, decidiuse combinar dúas funcións nunha soa. Como resultado, a produtividade aumentou 20 veces.
Paga a pena notar que non sempre se pode conseguir un resultado tan destacado. Nalgúns casos, o rendemento baixará, polo que paga a pena avaliar cada caso.
Como conclusión, podemos dicir que Wasm ofrece unha oportunidade para mellorar o rendemento da aplicación, pero cómpre usalo con prudencia.