WebAssembly: o que e como


Este artigo é baseado na minha apresentação na conferência ITSubbotnik, realizada em 2 de novembro de 2019 em Moscou.


Em geral, sou um programador de back-end, mas estava interessado nessa tecnologia, que me permite usar meu conhecimento de back-end na frente.


O problema


Vamos começar com o problema que está sendo resolvido por essa tecnologia (relativamente nova). Esse problema é executar rapidamente o código em um navegador . Rápido - significa "mais rápido que JavaScript", idealmente tão rápido quanto o nosso processador atual permite.
Além disso, historicamente, requisitos adicionais importantes surgiram gradualmente em torno desse problema:


  • Configuração zero - deve ser uma solução "pronta para uso", nada além de um navegador.
  • Seguro - a nova tecnologia não deve criar novas ameaças, já temos algo a ver com segurança.
  • Plataforma cruzada - os navegadores são executados em todos os principais processadores, incluindo plataformas móveis.
  • Conveniente para desenvolvedores - ou seja, para nós.

História antes de Wasm


Vimos muitas opções para executar código em um navegador. Podemos dizer que existem vencedores e perdedores neste campo.



Vencedores: Este é definitivamente JavaScript; o mecanismo V8 que tornou o JS tão rápido; bem como HTML5.


Perdedores: ActiveX - se você se lembra, essa tecnologia permite que você faça qualquer coisa com a máquina em geral, ou seja, a segurança era muito ruim; Flash - agora estamos testemunhando a era do declínio do Flash, embora o ActionScript funcione dentro dele, essencialmente o mesmo JavaScript; Silverlight - ele deve ter aparecido tarde demais para ocupar um nicho sério.
Como resultado, todos os plugins foram perdidos, inclusive devido a problemas de segurança.


Houve outras tentativas para resolver o problema, já no navegador:


  • NaCl - Cliente nativo proposto pelo Google; código nativo diretamente no navegador, o que naturalmente atrai a plataforma cruzada; A Mozilla não apoiou essa iniciativa, como resultado, a implementação foi apenas no Chrome.
  • PNaCl - Portable Native Client - um subconjunto de LLVM IR foi usado como código portátil; também não era suportado no Mozilla, novamente apenas no Chrome. Como resultado, o Google se recusou a oferecer suporte ao PNaCl em maio de 2017.

asm.js


O asm.js é outra iniciativa interessante, já da Mozilla Foundation, que nos aproxima do tópico WebAssembly. Apareceu em 2010 e, em 2013, tornou-se disponível ao público.


asm.js é um subconjunto de JavaScript, você pode compilar código de C e C ++ usando o compilador Emscripten.


Como também é JavaScript, esse código será executado em qualquer navegador. Além disso, os principais navegadores modernos conseguem reconhecer rapidamente o asm.js e compilá-lo com eficiência no código nativo do processador. Comparado ao código nativo obtido diretamente do C / C ++, o código obtido do asm.js é mais lento em apenas 1,5-2 vezes (50-67%).



À esquerda, está o código da função mais simples em C / C ++, à direita, é mostrado o que transforma após a compilação em asm.js. Primeiramente, vemos a linha 'use asm' , este é um marcador, que deixa claro que o código para asm.js segue em seguida. E neste código, vemos construções no formato |0 , esta é uma operação OR bit a bit com valor zero. De acordo com a especificação, o resultado desta operação é um número inteiro assinado de 32 bits. Mas esse tipo nem está em JavaScript. No entanto, esse tipo surge como resultado dessa operação, ou seja, é essencialmente uma conversão para um determinado tipo.


Em geral, asm.js é o uso de nosso conhecimento de como o mecanismo do navegador compila JS para otimizar este trabalho.


O que é o WebAssembly?



O WebAssembly (ou Wasm ) é um formato binário executado em um navegador, uma máquina virtual e o resultado da compilação a partir de um idioma de alto nível.


Wasm não é uma linguagem de programação, assim como o bytecode Java não é uma linguagem de programação, mas um resultado de compilação e um bloco de código em execução.


Alguém muito esperto disse que o nome web assembly (ou seja, "assembler para a web") está completamente incorreto, porque não é assembler (não é uma linguagem de programação) e não tem nada a ver com a web (porque é apenas uma máquina virtual).


Os criadores do WebAssembly foram guiados pelos seguintes objetivos e limitações - veja o vídeo Evolving Wasm em um nome impróprio apropriado: Andreas Rossberg .



Na verdade, eles se resumem a três coisas - multiplataforma, compacta, velocidade. Mas havia outro requisito importante: era "vendabilidade" - os desenvolvedores dos principais navegadores deveriam ter tomado e tomado a iniciativa. Como resultado, foi possível "vender", representantes do Google, Mozilla, Microsoft e Apple participaram do desenvolvimento da especificação.


Vamos ver o que Wasm é como uma máquina virtual.



Este é um "processador fictício", mas sem registros, tudo é feito através da pilha. Apenas quatro tipos de dados: dois inteiros, dois flutuantes. Conjunto de operações relativamente simples - consulte a especificação e a tabela interativa .



Modelo de memória plana: um único bloco é alocado para a memória, cujo tamanho é múltiplo de 64 KB. Aqui estão o código, dados, constantes, variáveis ​​globais, a pilha crescendo, a pilha crescendo. Você pode fazer o heap crescer automaticamente, se necessário, enquanto o bloco de memória se expande em um múltiplo de 64 KB.


Ponteiros não são usados ​​(isso é feito por segurança); um índice é usado. O índice é de 32 bits e, portanto, endereça até 4 GB de memória.


Toda a memória do WebAssembly é totalmente acessível a partir do JavaScript, tanto para leitura quanto para gravação.



Vamos dar uma olhada no modelo de tempo de execução do WebAssembly. Wasm é sempre carregado e chamado SOMENTE do JavaScript. Além disso, JS e Wasm trabalham na mesma caixa de proteção e são executados pelo mesmo mecanismo.


Observe que você também pode chamar JS do Wasm. Pode ser uma chamada de função com passagem de argumentos e retorno de um valor, ou pode estar apenas executando uma sequência arbitrária como código JS.


Tentando WebAssembly


Para começar o WebAssembly, recomendo usar o site WasmFiddle ou o WebAssembly Studio - essa é uma maneira simples e visual de entender por si mesmo o que realmente é o Wasm.



Aqui, o código-fonte em C / C ++ está no canto superior esquerdo (neste caso, a função recursiva para calcular o número de Fibonacci), no canto superior direito é o código JS para carregar o Wasm, instanciar o módulo Wasm e chamar a função fib() partir dele. Quando pressionamos o botão Build, obtemos um bloco de código Wasm (arquivo .wasm), que sempre podemos expandir para uma representação textual (arquivo .wat).


Essa representação textual com um monte de colchetes é essencialmente uma árvore de sintaxe abstrata (AST). Bem, na verdade, com um bracketing, ele se parece com a linguagem Lisp. Em teoria, podemos editar o código como uma representação de texto e, em seguida, recolhê-lo novamente em um formato binário - isso é uma reminiscência da programação em linguagem assembly. Mas geralmente obtemos Wasm binário como resultado da compilação de uma linguagem de alto nível.


2017: Produção pronta


Em novembro de 2017, o WebAssembly foi declarado "pronto para uso na produção". A especificação para todas as partes principais do Wasm foi preparada, a implementação do Wasm foi lançada em todos os principais navegadores. Assim, para o WebAssembly, o MVP foi lançado - Produto Mínimo Viavel, versão 1.0, com o qual estamos lidando agora.


Suporte do navegador


No final de 2017, foram lançadas as versões de todos os principais navegadores com suporte para WebAssembly:



A exceção é o IE11, não há suporte para isso e, provavelmente, ele desapareceu. Supunha-se que, para navegadores mais antigos, haverá um polyfill - a capacidade de converter o Wasm em asm.js; existem tais protótipos, mas até onde eu vi, esses projetos são abandonados, aparentemente, a comunidade não depende deles.


Agora, entre todos os navegadores instalados, ~ 88% suportam o Wasm .



Suporte de idioma


Para que seu idioma favorito seja compilado no Wasm, você precisa do compilador para fornecer esse objetivo de compilação. Agora, muitos idiomas suportam o Wasm, e há mais e mais deles todos os meses. Veja appcypher / awesome-wasm-langs .


  • C / C ++ - através do Emscripten , suporte muito bom.
  • Rust - O suporte Wasm apareceu há muito tempo, o ecossistema em torno de Wasm é construído em grande parte com base no Rust.
  • Java - por meio do TeaVM, JWebAssembly, Bytecoder - em um nível experimental.
  • Kotlin - existe suporte no Kotlin / Native via LLVM backend - experimental.
  • Go
  • C # - através do Blazor (mono) e no futuro na plataforma Uno .
  • TypeScript - através do AssemblyScript .

Não faz muito tempo, havia notícias de que o LLVM agora suporta o Wasm como um destino de compilação. Isso torna mais fácil para os desenvolvedores de linguagens de programação compilarem ainda mais linguagens no Wasm.


Casos de uso


Esta é provavelmente uma das principais perguntas - "Como posso usar o Wasm?"


O WebAssembly já está usando ativamente:


  • Jogos, mecanismos de jogos, mecanismos de física, VR / AR - por exemplo, Godot , Doom 3
  • Emuladores, máquinas virtuais - por exemplo, DOSBox
  • Editores gráficos / 3D - Figma , AutoCAD
  • Clientes da Web para plataformas de negociação financeira - vi apresentações sobre dois desses clientes
  • Codecs e filtros de áudio / vídeo - por exemplo, ffmpeg
  • Bancos de dados - por exemplo, sqlite

Outros cenários possíveis:


  • Aplicativos da Web progressivos (PWA)
  • Reconhecimento por uma rede neural treinada

Desempenho


O desempenho do wasm foi um dos principais fatores de venda, mas o que realmente acontece?


Comparado ao JavaScript, verifica-se que, em média, o Wasm é mais rápido, mas em cada caso específico você precisa fazer uma comparação JS / Wasm, porque pode ser muitas vezes melhor e várias vezes pior. Também pode ser altamente dependente do navegador usado.


De fato, o desempenho máximo de JS e Wasm é o mesmo, pois ambos acabam se transformando em código de processador nativo. Mas o JS é muito mais fácil de perder no desempenho, e o Wasm fornece uma abordagem mais "uniforme".


Como regra, o Wasm tem um bom desempenho na computação volumétrica. Onde existem muitas operações de memória, o Wasm perde. Bem, o principal problema em aplicativos reais é a lenta interoperabilidade JS <-> Wasm. Veja, por exemplo, uma referência .



Em julho de 2019, o artigo científico “Não é tão rápido: analisando o desempenho do WebAssembly vs. Código nativo " . Os autores implementaram a capacidade de executar utilitários de console Linux no WebAssembly para executar benchmarks e usaram benchmarks SPEC para avaliar o desempenho do Wasm em comparação com os mesmos testes em asm.js. e código nativo.


Os resultados são os seguintes:


  • Wasm 30% mais rápido que JavaScript (média para esses testes)
  • Wasm é 50% mais lento que o código nativo (em média nesses testes)

Os autores do artigo também analisaram os motivos pelos quais Wasm "desacelera":


  • cerca de duas vezes mais operações de carregamento / salvamento de dados em comparação com o código nativo;
  • mais ramificações - causadas pela necessidade de verificações adicionais ao acessar a memória;
  • mais falta o cache L1 passado.

Em geral, de fato, o desempenho não é tão ruim. Além disso, essa análise permitirá que os desenvolvedores de navegadores tornem o Wasm ainda mais rápido.


No futuro, o Wem acelerará não apenas devido a uma melhor otimização nos navegadores, mas também a novos recursos, como: operações de bloqueio de memória, suporte para instruções SIMD, suporte para threads.


O que acontecerá depois?


Como o WebAssembly está se desenvolvendo?


Primeiro, a equipe de especificação para Wasm continua seu trabalho. As especificações estão em diferentes estágios (fases), existe um certo "roteiro" para este trabalho.


Em particular, em um futuro próximo, esperamos ver ainda mais esses recursos:


  • Conversões de flutuação para int sem captura - agora a conversão de um valor flutuante para um número inteiro em algumas condições pode causar uma exceção; Para um programador, isso é inesperado; portanto, todas essas conversões precisam ser concluídas, perdendo o desempenho. Esse recurso resolve o problema.
  • Múltiplos valores - a capacidade de retornar mais de um valor de uma função, a capacidade de criar novas instruções que retornam mais de um valor - por exemplo, o resultado da divisão e o restante da divisão, ou o resultado da adição e do bit de transporte.
  • Tipos de referência é uma introdução ao tipo anyref, que significa "link para algo no heap JS", o primeiro passo para acelerar a interação com o JS.

Em segundo lugar, os desenvolvedores de navegadores, por sua vez, implementam essas especificações, ou seja, gradualmente, novos recursos são adicionados ao Wasm, primeiro ocultos "sob a bandeira" nas configurações e depois ativados por padrão.


Por exemplo, aqui está uma lista de recursos do Chrome relacionados ao WebAssembly .
Para o Firefox, uma lista semelhante pode ser encontrada aqui .


WebAssembly fora do navegador


Como mencionado acima, o Wasm não está essencialmente conectado à Web, é apenas uma máquina virtual. Isso significa que também pode ser usado fora da web.


Agora, existem vários cenários para o uso do Wasm fora do navegador:


  • Node.js - O Node.js é baseado no mecanismo V8 que suporta Wasm.
  • Um aplicativo de console separado, o código do aplicativo é executado no Wasm VM - exemplos desse tempo de execução: wasmtime , wasmer.
  • O Wasm VM é usado como uma biblioteca de outros idiomas - por exemplo, o wasmer permite que você se chame de uma dúzia de idiomas diferentes.

Para o Wasm trabalhando fora do navegador, as restrições do sandbox não são mais necessárias; pelo contrário, o acesso às funções do sistema é necessário - o sistema de arquivos e os arquivos, E / S do console etc. Isso levou à criação da WebAssembly System Interface (WASI), uma especificação de API de plataforma cruzada semelhante ao POSIX. Consulte WebAssembly / WASI e wasi.dev .



O próximo passo foi criar um gerenciador de pacotes - Wasm Package Manager (WAPM) - wapm.io. Aqui você pode pegar o arquivo .wasm finalizado e usá-lo em seu aplicativo. Normalmente, estamos falando de versões Wasm de algumas bibliotecas conhecidas. Alguns pacotes são marcados com a tag WASI, o que significa que eles só podem ser usados ​​em cenários fora do navegador.


Conclusão


Portanto, o WebAssembly é bem possível de usar, já está "pronto para produção" há dois anos.
O uso do Wasm pode muito bem acelerar o código JavaScript semelhante, mas você deve sempre verificar se recebe um aumento de velocidade.
O suporte Wasm das linguagens de programação está em constante evolução.


Bem, e mais importante, o WebAssembly “mudou o cenário” da Web - nos forneceu novos cenários de uso que podemos implementar em nossos aplicativos.


Referências



Listagens impressionantes:



Vídeo:


Source: https://habr.com/ru/post/pt475778/


All Articles