WebAssembly (wasm) es un formato portátil de instrucciones binarias. El mismo código de código wasm se puede ejecutar en cualquier entorno. Para respaldar esta declaración, cada idioma, plataforma y sistema debe poder ejecutar dicho código, por lo que es lo más rápido y seguro posible.
 Wasmer
 Wasmer es un tiempo de ejecución wasm escrito en 
Rust . Obviamente, el lavador se puede usar en cualquier aplicación de Rust. El autor del material, una traducción que publicamos hoy, dice que él y otros participantes en el proyecto Wasmer implementaron con éxito este tiempo de ejecución de código wasm en otros idiomas:
Aquí hablaremos sobre un nuevo proyecto: 
go-ext-wasm , que es una biblioteca para Go, diseñada para ejecutar código binario wasm. Al final resultó que, el proyecto go-ext-wasm es mucho más rápido que otras soluciones similares. Pero no nos adelantemos a nosotros mismos. Comencemos con una historia sobre cómo trabajar con él.
Llamar a funciones wasm desde Go
Para comenzar, instale wasmer en un entorno Go (con soporte cgo).
export CGO_ENABLED=1; export CC=gcc; go install github.com/wasmerio/go-ext-wasm/wasmer 
El proyecto 
go-ext-wasm es una biblioteca Go normal. Cuando se trabaja con esta biblioteca, 
import "github.com/wasmerio/go-ext-wasm/wasmer" la construcción de 
import "github.com/wasmerio/go-ext-wasm/wasmer" .
Ahora vamos a practicar. Vamos a escribir un programa simple que compila en wasm. Usaremos para esto, por ejemplo, Rust:
 #[no_mangle] pub extern fn sum(x: i32, y: i32) -> i32 {   x + y } 
Llamamos al archivo con el programa 
simple.rs , como resultado de compilar este programa obtenemos el archivo 
simple.wasm .
El siguiente programa, escrito en Go, realiza la función de 
sum del archivo wasm, pasándole los números 5 y 37 como argumentos:
 package main import (   "fmt"   wasm "github.com/wasmerio/go-ext-wasm/wasmer" ) func main() {    
Aquí, un programa escrito en Go llama a una función de un archivo wasm que se obtuvo compilando código escrito en Rust.
Entonces, el experimento fue un éxito, ejecutamos con éxito el código de WebAssembly en Go. Cabe señalar que la conversión del tipo de datos es automática. Los valores de Go que se pasan al código wasm se convierten en tipos de WebAssembly. Lo que devuelve la función wasm se convierte en tipos Go. Como resultado, trabajar con funciones de archivos wasm en Go se ve igual que trabajar con funciones Go normales.
Funciones de llamada desde el código de WebAssembly
Como vimos en el ejemplo anterior, los módulos de WebAssembly pueden exportar funciones a las que se puede llamar desde afuera. Este es el mecanismo que permite que el código wasm se ejecute en varios entornos.
Al mismo tiempo, los módulos WebAssembly pueden funcionar con funciones importadas. Considere el siguiente programa escrito en Rust.
 extern {   fn sum(x: i32, y: i32) -> i32; } #[no_mangle] pub extern fn add1(x: i32, y: i32) -> i32 {   unsafe { sum(x, y) } + 1 } 
Asigne un nombre al archivo con 
import.rs . Compilarlo en WebAssembly dará como resultado un código que se puede encontrar 
aquí .
La función 
add1 exportada llama a la función 
sum . No hay implementación de esta función, solo su firma se define en el archivo. Esta es la llamada función externa. Para WebAssembly, esta es una función importada. Su implementación debe ser importada.
Implementamos la función de 
sum usando Go. Para esto necesitamos usar 
cgo . Aquí está el código resultante. Algunos comentarios, que son descripciones de los fragmentos de código principales, están numerados. A continuación hablaremos sobre ellos con más detalle.
 package main  
Analicemos este código:
- La firma de la función sumse define en C (consulte el comentario sobre el comando deimport "C").
- La implementación de la función de sumse define en Go (observe la línea//export- este mecanismo cgo usa para establecer la conexión del código escrito en Go con el código escrito en C).
- NewImportses una API utilizada para crear importaciones de WebAssembly. En este código,- "sum"es el nombre de la función importada por WebAssembly,- sumes el puntero a la función Go y- C.sumes el puntero a la función cgo.
- Y finalmente, NewInstanceWithImportses un constructor diseñado para inicializar un módulo WebAssembly con importaciones.
Leer datos de la memoria
La instancia de WebAssembly tiene memoria lineal. Hablemos sobre cómo leer datos de él. Comencemos, como de costumbre, con el código Rust, al que llamaremos 
memory.rs .
 #[no_mangle] pub extern fn return_hello() -> *const u8 {   b"Hello, World!\0".as_ptr() } 
El resultado de compilar este código está en el archivo 
memory.wasm , que se utiliza a continuación.
La función 
return_hello devuelve un puntero a una cadena. La línea termina, como en C, con un carácter nulo.
Ahora ve al lado Ir:
 bytes, _ := wasm.ReadBytes("memory.wasm") instance, _ := wasm.NewInstance(bytes) defer instance.Close()  
La función 
return_hello devuelve un puntero como un valor 
i32 . Obtenemos este valor llamando a 
ToI32 . Luego obtenemos los datos de la memoria usando 
instance.Memory.Data() .
Esta función devuelve el segmento de memoria de la instancia de WebAssembly. Puedes usarlo como cualquier rebanada Go.
Afortunadamente, sabemos la longitud de la línea que queremos leer, por lo tanto, para leer la información necesaria, es suficiente usar la construcción de 
memory[pointer : pointer+13] . Luego, los datos leídos se convierten en una cadena.
Aquí hay un ejemplo que muestra mecanismos de memoria más avanzados cuando se usa el código de WebAssembly de Go.
Puntos de referencia
El proyecto go-ext-wasm, como acabamos de ver, tiene una API conveniente. Ahora es tiempo de hablar sobre su desempeño.
A diferencia de PHP o Ruby, el mundo Go ya tiene soluciones para trabajar con código wasm. En particular, estamos hablando de los siguientes proyectos:
- Life from Perlin Network - Intérprete de WebAssembly.
- Go Interpreter's Wagon es un intérprete y kit de herramientas de WebAssembly.
El 
material del proyecto php-ext-wasm utilizó el algoritmo 
n-body para estudiar el rendimiento. Existen muchos otros algoritmos adecuados para examinar el rendimiento de los entornos de ejecución de código. Por ejemplo, este es el algoritmo de 
Fibonacci (versión recursiva) y 
el algoritmo Pollard ρ utilizado en Life. Este es el algoritmo de compresión Snappy. Este último funciona con éxito con go-ext-wasm, pero no con Life o Wagon. Como resultado, fue eliminado del conjunto de prueba. El código de prueba se puede encontrar 
aquí .
Durante las pruebas, se utilizaron las últimas versiones de los proyectos de investigación. A saber, estos son Life 20190521143330-57f3819c2df0 y Wagon 0.4.0.
Los números que se muestran en la tabla reflejan los valores promedio obtenidos después de 10 inicios de la prueba. El estudio utilizó el MacBook Pro 15 de 2016 "con un procesador Intel Core i7 de 2.9 GHz y 16 GB de memoria.
Los resultados de las pruebas se agrupan a lo largo del eje X de acuerdo con los tipos de pruebas. El eje Y muestra el tiempo, en milisegundos, requerido para completar la prueba. Cuanto más pequeño sea el indicador, mejor.
 Comparación de rendimiento de Wasmer, Wagon y Life utilizando implementaciones de varios algoritmos
Comparación de rendimiento de Wasmer, Wagon y Life utilizando implementaciones de varios algoritmosLas plataformas Life y Wagon, en promedio, dan aproximadamente los mismos resultados. Wasmer, en promedio, es 72 veces más rápido.
Es importante tener en cuenta que Wasmer admite tres backends: 
Singlepass , 
Cranelift y 
LLVM . El backend predeterminado en la biblioteca Go es Cranelift ( 
aquí puede encontrar más información al respecto). El uso de LLVM proporcionará un rendimiento cercano al nativo, pero se decidió comenzar con Cranelift, ya que este backend proporciona la mejor relación entre el tiempo de compilación y el tiempo de ejecución del programa.
Aquí puede leer sobre diferentes backends, sus pros y sus contras, y en qué situaciones es mejor usarlos.
Resumen
El proyecto de código abierto 
go-ext-wasm es una nueva biblioteca Go diseñada para ejecutar código binario wasm. Incluye un 
tiempo de ejecución Wasmer . Su primera versión incluye API, cuya necesidad surge con mayor frecuencia.
Las pruebas de rendimiento mostraron que Wasmer, en promedio, es 72 veces más rápido que Life y Wagon.
Estimados lectores! ¿Planea utilizar la capacidad de ejecutar código wasm en Go usando go-ext-wasm?
