Demostración de WebAssembly

1. ¿Qué?


WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.

Un formato portátil, pequeño y de carga rápida (binario), adecuado para compilar en la Web

El objetivo principal es admitir aplicaciones de alto rendimiento en el entorno web. Pero el diseño no se basa en características web, ni proporciona funciones para características web, y también se puede usar en otros entornos.

Una comprensión simple es definir un formato de destino de compilación que pueda lograr un rendimiento de ejecución casi nativo en cualquier entorno que admita este formato. Equivale a permitir la expansión de módulos nativos. En escenarios de rendimiento crítico, use otros lenguajes más adecuados (como C ++) para implementar y luego compile en WebAssembly por adelantado, puede obtener una experiencia de rendimiento comparable a la nativa

Los objetivos del diseño se dividen en 2 aspectos:

Semántica rápida, segura y portátil

Rápido: ejecute con un rendimiento cercano al código nativo y utilice funciones comunes a todo el hardware moderno

Seguridad: el código se verifica y ejecuta en un entorno de zona de pruebas seguro para la memoria para evitar la corrupción de datos o violaciones de seguridad

Bien definido: definición completa y precisa de los procedimientos legales y su comportamiento, de manera que sea fácil inferir informal y formal

Independiente del hardware: compile en todas las arquitecturas modernas, dispositivos de escritorio o móviles y sistemas integrados

Independiente del lenguaje: sin sesgo hacia ningún lenguaje específico, modelo de programación o modelo de objeto

Independiente de la plataforma: puede integrarse en el navegador, ejecutarse como una máquina virtual independiente o integrarse en otros entornos

Abierto: los programas pueden interactuar con su entorno de forma sencilla y universal

Representación eficiente y portátil

Pequeño y exquisito: el formato binario es más pequeño que el texto típico o el formato de código nativo y se puede transmitir rápidamente

Modularidad: el programa se puede dividir en partes más pequeñas, que se pueden transmitir, almacenar en caché y utilizar por separado

Eficiente: se puede decodificar, verificar y compilar rápidamente en una sola pasada (recorrido), lo que equivale a la compilación en tiempo real (JIT) o antes de tiempo (AOT)

Streaming: permite comenzar a decodificar, verificar y compilar lo antes posible antes de que todos los datos estén disponibles

Paralelo: permite que la decodificación, verificación y compilación se dividan en múltiples tareas paralelas independientes

Portabilidad: sin suposiciones sobre arquitecturas que no son ampliamente compatibles con hardware moderno

Los principales navegadores (Chrome, Edge, Firefox y WebKit) promueven conjuntamente el proceso de estandarización:


WebAssembly is currently being designed as an open standard by a W3C Community Group that includes representatives from all major browsers.

PD: Esto está liderado por los fabricantes de navegadores (los cuatro se unen para hacer cosas, vale la pena esperar), por cierto, estándares abiertos (no solo para el entorno web), la motivación proviene del deseo de mejorar aún más el rendimiento del tiempo de ejecución de JS, en V8 Después de la introducción de JIT, es imposible mejorar aún más el rendimiento debido a las limitaciones de las características del lenguaje JS (como los tipos interpretados y débiles). Las capacidades web son cada vez más fuertes, el cliente JS es cada vez más pesado y la necesidad de mejorar aún más el rendimiento de ejecución de JS sigue ahí, por lo que existe el resultado final de WebAssembly

2. Wasm y wast
Sabemos que WebAssembly define un formato binario, este formato es wasm, por ejemplo:


0061 736d 0100 0000 0187 8080 8000 0160
027f 7f01 7f03 8280 8080 0001 0004 8480
8080 0001 7000 0005 8380 8080 0001 0001
0681 8080 8000 0007 9080 8080 0002 066d
656d 6f72 7902 0003 6763 6400 000a ab80
8080 0001 a580 8080 0001 017f 0240 2000
450d 0003 4020 0120 0022 026f 2100 2002
2101 2000 0d00 0b20 020f 0b20 010b 

El código C correspondiente a esta cadena de números hexadecimales es:


// 辗转相除法求最大公约数
int gcd(int m, int n) {
    if (m == 0) return n;
    return gcd(n % m, m);
}

La legibilidad de wasm es igual a 0. Para paliar este problema, se define un formato de texto con mejor legibilidad, llamado wast:


(module
 (table 0 anyfunc)
 (memory $0 1)
 (export "memory" (memory $0))
 (export "gcd" (func $gcd))
 (func $gcd (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (block $label$0
   (br_if $label$0
    (i32.eqz
     (get_local $0)
    )
   )
   (loop $label$1
    (set_local $0
     (i32.rem_s
      (get_local $1)
      (tee_local $2
       (get_local $0)
      )
     )
    )
    (set_local $1
     (get_local $2)
    )
    (br_if $label$1
     (get_local $0)
    )
   )
   (return
    (get_local $2)
   )
  )
  (get_local $1)
 )
)

Los paréntesis son un poco al estilo Lisp, pero al menos son legibles, por ejemplo:

// 导出了两个东西,分别叫`memory`和`gcd`
(export "memory" (memory $0))
(export "gcd" (func $gcd))
// 函数签名,接受2个int32类型参数,返回int32类型值
(func $gcd (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
// 函数体...就不猜了

PSwast y wasm se pueden convertir entre sí, consulte WABT: The WebAssembly Binary Toolkit para obtener más detalles

Además, puede ver otro comando de texto en el panel Fuente del navegador:


func (param i32 i32) (result i32)
(local i32)
  block
    get_local 0
    i32.eqz
    br_if 0
    loop
      get_local 1
      get_local 0
      tee_local 2
      i32.rem_s
      set_local 0
      get_local 2
      set_local 1
      get_local 0
      br_if 0
    end
    get_local 2
    return
  end
  get_local 1
end

Se parece mucho a wast, no sé si hay un nombre, o también pertenece a wast? Esto es convertido por el navegador basado en wasm

3.
Requisitos ambientales del entorno de juego de prueba :

Entorno de compilación C / C ++ Emscripten

Un navegador que admita WebAssembly (el último Chrome lo admite de forma predeterminada)


¿ Le duele el entorno online ? Entorno de demostración: WebAssembly Explorer

COMPILAR y DESCARGAR puede obtener wasm, es fácil de usar

Tenga en cuenta que el entorno predeterminado es C ++. Si desea utilizar C, seleccione C99 o C89 a la izquierda, de lo contrario, el nombre de la función se corromperá, como la pérdida de C ++ 11:


(module
 (table 0 anyfunc)
 (memory $0 1)
 (export "memory" (memory $0))
 (export "_Z3gcdii" (func $_Z3gcdii))
 (func $_Z3gcdii (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (block $label$0
   (br_if $label$0
    (i32.eqz
     (get_local $0)
    )
   )
   (loop $label$1
    (set_local $0
     (i32.rem_s
      (get_local $1)
      (tee_local $2
       (get_local $0)
      )
     )
    )
    (set_local $1
     (get_local $2)
    )
    (br_if $label$1
     (get_local $0)
    )
   )
   (return
    (get_local $2)
   )
  )
  (get_local $1)
 )
)

El nombre de la función se ha compilado en _Z3gcdii. Se supone que algo como el espacio de nombres está causando problemas. No estoy familiarizado con C ++, por lo que uso obedientemente C

PD Además de C / C ++, otros lenguajes también pueden reproducir WebAssembly, como Rust


Descargar el SDK de la plataforma para el entorno local

Siga los pasos de instalación

Si nada más, puede instalarlo aquí, puede probar emcc -v:


INFO:root:(Emscripten: Running sanity checks)
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.22
clang version 4.0.0  (emscripten 1.37.22 : 1.37.22)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: D:\emsdk-portable-64bit\clang\e1.37.22_64bit
INFO:root:(Emscripten: Running sanity checks)

En el entorno Windows, puede encontrar un error de DLL que falta (MSVCP140.dll). Puede instalar manualmente el entorno C ++ requerido. Para obtener más información, consulte MSVCP140.dll no encontrado · Número 5605 · kripken / emscripten

Luego puede intentarlo (guarde el código C anterior como un archivo gcd.c):

emcc ./c/gcd.c -Os -s WASM=1 -s SIDE_MODULE=1 -s BINARYEN_ASYNC_COMPILATION=0 -o ./output/gcd.wasm

PD Para obtener más información, consulte el tutorial de Emscripten

El contenido de gcd.wasm es el siguiente:


0061 736d 0100 0000 000c 0664 796c 696e
6b80 80c0 0200 010a 0260 027f 7f01 7f60
0000 0241 0403 656e 760a 6d65 6d6f 7279
4261 7365 037f 0003 656e 7606 6d65 6d6f
7279 0200 8002 0365 6e76 0574 6162 6c65
0170 0000 0365 6e76 0974 6162 6c65 4261
7365 037f 0003 0403 0001 0106 0b02 7f01
4100 0b7f 0141 000b 072b 0312 5f5f 706f
7374 5f69 6e73 7461 6e74 6961 7465 0002
0b72 756e 506f 7374 5365 7473 0001 045f
6763 6400 0009 0100 0a40 0327 0101 7f20
0004 4003 4020 0120 006f 2202 0440 2000
2101 2002 2100 0c01 0b0b 0520 0121 000b
2000 0b03 0001 0b12 0023 0024 0223 0241
8080 c002 6a24 0310 010b 

Tenga en cuenta que el nombre del método tendrá como prefijo un guión bajo (_) de forma predeterminada. En este ejemplo, el nombre del método exportado es _gcd. Para obtener más información, consulte Interactuar con el código:


The keys passed into mergeInto generate functions that are prefixed by _. In other words myfunc: function() {}, becomes function _myfunc() {}, as all C methods in emscripten have a _ prefix. Keys starting with $ have the $ stripped and no underscore added.

La interfaz del módulo utilizada en JS debe estar subrayada (no sé si hay un elemento de configuración que pueda eliminarlo)

Cuatro. Pruébalo


WebAssembly.compile(new Uint8Array(`
    0061 736d 0100 0000 0187 8080 8000 0160
    027f 7f01 7f03 8280 8080 0001 0004 8480
    8080 0001 7000 0005 8380 8080 0001 0001
    0681 8080 8000 0007 9080 8080 0002 066d
    656d 6f72 7902 0003 6763 6400 000a ab80
    8080 0001 a580 8080 0001 017f 0240 2000
    450d 0003 4020 0120 0022 026f 2100 2002
    2101 2000 0d00 0b20 020f 0b20 010b 
    `.match(/\S{2}/g).map(s => parseInt(s, 16))
)).then(module => {
    const instance = new WebAssembly.Instance(module);
    console.log(instance.exports);
    const { gcd } = instance.exports;
    console.log('gcd(328, 648)', gcd(328, 648));
});

La cadena hexadecimal proviene de la demostración en línea, que es consistente con el ejemplo original de wasm. Simplemente coloque estas cosas en la consola de Chrome para su ejecución. Si todo es normal, obtendrá un error:


VM40:1 Uncaught (in promise) CompileError: WasmCompile: Wasm code generation disallowed in this context

Esto se debe a que las restricciones predeterminadas de CSP (Política de seguridad de contenido) son fáciles de resolver, solo active el modo de incógnito (Ctrl / CMD + Shift + N)

Obtendrá la salida:


{memory: Memory, gcd: ƒ}
gcd(328, 648) 8

La primera línea es el contenido de exportación del módulo obtenido al cargar nuestro WebAssembly, incluido un objeto de memoria y un método gcd, y la salida de la segunda línea es el máximo común divisor calculado llamando al módulo de alto rendimiento

WebAssembly.compile y otras API relacionadas pueden hacer referencia a:

JavaScript API-WebAssembly: Definición de especificación

WebAssembly-JavaScript | MDN: contiene ejemplos

Además, la versión compilada localmente requiere importaciones env (y el nombre de la función tiene el prefijo _):


WebAssembly.compile(new Uint8Array(`
    0061 736d 0100 0000 000c 0664 796c 696e
    6b80 80c0 0200 010a 0260 027f 7f01 7f60
    0000 0241 0403 656e 760a 6d65 6d6f 7279
    4261 7365 037f 0003 656e 7606 6d65 6d6f
    7279 0200 8002 0365 6e76 0574 6162 6c65
    0170 0000 0365 6e76 0974 6162 6c65 4261
    7365 037f 0003 0403 0001 0106 0b02 7f01
    4100 0b7f 0141 000b 072b 0312 5f5f 706f
    7374 5f69 6e73 7461 6e74 6961 7465 0002
    0b72 756e 506f 7374 5365 7473 0001 045f
    6763 6400 0009 0100 0a40 0327 0101 7f20
    0004 4003 4020 0120 006f 2202 0440 2000
    2101 2002 2100 0c01 0b0b 0520 0121 000b
    2000 0b03 0001 0b12 0023 0024 0223 0241
    8080 c002 6a24 0310 010b 
    `.match(/\S{2}/g).map(s => parseInt(s, 16))
)).then(module => {
    let imports = {
        env: {
            memoryBase: 0,
            memory: new WebAssembly.Memory({ initial: 256 }),
            tableBase: 0,
            table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
        }
    };
    const instance = new WebAssembly.Instance(module, imports);
    console.log(instance.exports);
    // 注意下划线前缀
    const { _gcd } = instance.exports;
    console.log('gcd(328, 648)', _gcd(328, 648));
});

Puede obtener un resultado similar:


{__post_instantiate: ƒ, runPostSets: ƒ, _gcd: ƒ}
gcd(328, 648) 8

Debería ser que Emscripten haya agregado algunas cosas irrelevantes por defecto, que son funcionalmente equivalentes a nuestra versión simplificada

V.
Ventajas, desventajas y escenarios de aplicación El
tamaño del código es pequeño

Aproximadamente 300k (comprimido) la lógica de JavaScript se reescribe con WebAssembly, el volumen es de solo 90k

Pero el uso de WebAssembly requiere la introducción de una biblioteca de clases JavaScript de 50k-100k como infraestructura

La seguridad se mejora ligeramente

Aunque las instrucciones de texto de WebAssembly correspondientes al código fuente aún no están ocultas, el costo inverso es mayor

Mejora del rendimiento

En teoría, WebAssembly tiene un rendimiento de ejecución cercano al nativo, porque omite el proceso de interpretación y el tamaño del archivo también tiene ventajas en términos de transmisión.

Por supuesto, la premisa es que en escenarios donde la cantidad de código comercial es grande y se requiere un rendimiento extremo, en escenarios de ejecución repetida como los puntos de referencia, JIT no es mucho más lento que AOT.

Desventajas
capacidad actualmente limitada:

Solo se admiten algunos tipos de datos básicos (i32 / i64 / f32 / f64 / i8 / i16)

Sin acceso directo a DOM y otras API web

Incapaz de controlar GC

Escenario de aplicación
WebAssembly define un formato binario ejecutable estándar para navegadores, de modo que más desarrolladores puedan participar a través de un mecanismo de compilación unificado para construir un ecosistema Web próspero La visión es buena, pero existen algunos problemas prácticos.

En primer lugar, la intención original de WebAssembly es "admitir aplicaciones de alto rendimiento en el entorno web". Para superar el cuello de botella de rendimiento, los posibles escenarios de aplicación son:

Decodificación de video

Procesamiento de imágenes

Visualización 3D / WebVR / AR

Motor de renderizado

Motor de física

Algoritmo de compresión / encriptación

… Etc. Escenas con mucho cálculo

Por supuesto, es posible que en el futuro también se integre algo de soporte en el navegador, en lugar de usar "extensiones" o similares. Pero el significado real de WebAssembly es proporcionar la capacidad de permitir la autoextensión de módulos "nativos" de alto rendimiento. Después de todo, puede llevar mucho tiempo esperar a que el navegador lo proporcione y esperar hasta que la compatibilidad sea aceptable. Con esta capacidad, No es necesario esperar a que los navegadores principales del mercado admitan una determinada función nativa, puede hacerlo usted mismo y no hay diferencia de compatibilidad. Por el contrario, puede surgir un lote de módulos comunitarios populares y gradualmente ser adoptados como soporte nativo del navegador, devolviendo ecológicamente al entorno web.


WebAssembly de referencia

WebAssembly en la práctica: cómo escribir código: una gran guía

¿Cómo comentar sobre la última tecnología de código de bytes de WebAssembly en los navegadores?

WebAssembly: ¿La bala de plata para resolver los problemas crónicos de JavaScript?

WebAssembly, la nueva era de la Web

¿Se puede polrelleno WebAssembly?

wasm-arrays: biblioteca de empaquetado de matrices WebAssembly

Supongo que te gusta

Origin blog.51cto.com/15080030/2592698
Recomendado
Clasificación