Почему WASM — это будущее Интернета?

внешний интерфейс WebAssembly
Почему WASM — это будущее Интернета?

О чем будет эта статья?

Узнайте о прошлом и настоящем WebAssembly, о том, как это великое творение, призванное сделать Интернет более широко используемым, работает на протяжении всего жизненного цикла Web/Node.js, и узнайте, почему WASM — это будущее Интернета?

В этой статье вы узнаете о собственных компиляторах WebAssembly, AssemblyScript и Emscripten.

Наконец, будущее WebAssembly рассматривается, и перечислены некоторые интересные направления развития технологий.

Я также писал статьи о глубоком понимании использования WebAssembly и отладке кода WebAssembly в браузере. Заинтересованные студенты могут щелкнуть ссылку, чтобы прочитать:

Зачем вам WebAssembly?

динамический языковой каблук

Во-первых, давайте посмотрим на процесс выполнения кода JS:

image.png

Выше показана структура движка ChakraCore до Microsoft Edge.В настоящее время движок JS Microsoft Edge переведен на V8.

Общий процесс таков:

  • Получите исходный код JS, передайте его парсеру и сгенерируйте AST
  • Компилятор ByteCode компилирует AST в байт-код (ByteCode)
  • ByteCode входит в транслятор, транслятор построчно переводит байт-код (Interpreter) в машинный код (Machine Code), а затем выполняет

Но на самом деле код, который мы обычно пишем, имеет множество мест, которые можно оптимизировать, например, если одна и та же функция выполняется несколько раз, сгенерированный этой функцией машинный код можно пометить как оптимизированный, а затем упаковать и отправить в JIT. Компилятор (Just-In-Time), следующий. При повторном выполнении этой функции нет необходимости проходить процесс Parser-Compiler-Interpreter, а подготовленный машинный код может выполняться напрямую, что значительно повышает эффективность выполнения кода.

Однако приведенная выше JIT-оптимизация может использоваться только для статически типизированных переменных, таких как функция, которую мы хотим оптимизировать, она имеет только два параметра, и тип каждого параметра определен, но JavaScript является динамически типизированным языком, что также означает , во время выполнения функции тип может меняться динамически, параметров может стать три, а тип первого параметра может измениться с объекта на массив, что приведет к сбою JIT, а парсер-компилятор- Interpreter-Execution необходимо выполнить снова, а два шага Parser-Compiler являются двумя наиболее трудоемкими шагами во всем процессе выполнения кода, поэтому в контексте языка JavaScript Web не может выполнять некоторые высокопроизводительные операции. высокопроизводительные приложения, такие как крупномасштабные игры, видеоклипы и т. д.

Оптимизация статического языка

Согласно приведенному выше описанию, одной из основных причин медленного выполнения JS является то, что JIT недействителен из-за особенностей его динамического языка.Поэтому, если мы сможем ввести в JS статические характеристики, мы сможем поддерживать эффективную JIT, которая неизбежно ускорит выполнение JS.Скорость, на этот раз появился asm.js.

ASM.JS предоставляет только два типа данных:

  • 32-битное целое число со знаком
  • 64-битное число с плавающей запятой со знаком

Другие, такие как строки, логические значения или объекты, хранятся в памяти как числа, вызываемые через TypedArray. Целые числа и числа с плавающей запятой представлены следующим образом:

ArrayBufferобъект,TypedArrayвид иDataViewПредставление — это интерфейс для управления двоичными данными в JavaScript, который обрабатывает двоичные данные в синтаксисе массива, который в совокупности называется двоичным массивом. Ссылаться наArrayBuffer.

var a = 1;

var x = a | 0;  // x 是32位整数
var y = +a;  // y 是64位浮点数

Функция записывается следующим образом:

function add(x, y) {
  x = x | 0;
  y = y | 0;
  return (x + y) | 0;
}

Вышеупомянутые параметры функции и возвращаемые значения должны объявлять тип, здесь все 32-битные целые числа.

Более того, в asm.js не предусмотрен механизм сборки мусора, операции с памятью контролируются самими разработчиками, а память напрямую читается и пишется через TypedArray:

var buffer = new ArrayBuffer(32768); // 申请 32 MB 内存
var HEAP8 = new Int8Array(buffer); // 每次读 1 个字节的视图 HEAP8
function compiledCode(ptr) {
  HEAP[ptr] = 12;
  return HEAP[ptr + 4];
}

Из вышеизложенного видно, что asm.js — это строгое подмножество JavaScript, которое требует, чтобы тип переменных определялся и оставался неизменным во время выполнения, и удаляет механизм сборки мусора, которым обладает JavaScript, требуя от разработчиков вручную управлять памятью. Таким образом, JS-движок может выполнять множество JIT-оптимизаций на основе кода asm.js.По статистике скорость выполнения asm.js в браузере составляет около 50% от нативного кода (машинного кода).

Инновации

Но как бы ни был статичен asm.js, он по-прежнему относится к области JavaScript, чтобы избавиться от некоторых трудоемких абстракций верхнего уровня (сборка мусора и т. д.), а выполнение кода также требует двух процессов Parser-Compiler , которые также являются кодом, требующим больше всего времени для выполнения.

Ради максимальной производительности веб-разработчики внешнего интерфейса отказались от JavaScript, создали язык ассемблера WebAssembly, который может напрямую работать с машинным кодом, и напрямую убили Parser-Compiler.В то же время WebAssembly является строго типизированным статическим языком, может максимизировать JIT-оптимизацию WebAssembly делает скорость WebAssembly бесконечно близкой к собственному коду, такому как C/C++.

Эквивалентно следующему процессу:

Его можно выполнять напрямую без использования Parser-Compiler, устраняя при этом механизм сборки мусора, а статические и строго типизированные языковые функции WASM обеспечивают максимальную JIT-оптимизацию.

Первый взгляд на WebAssembly

Мы можем интуитивно понять расположение WebAssembly в сети по картинке:

WebAssembly (также известный как WASM) — это новый языковой формат, который может работать в Интернете. Он отличается небольшим размером, высокой производительностью и высокой переносимостью. также признан W3C. 4-й язык в Интернете.

Есть несколько причин, по которым он похож на JavaScript на нижнем уровне:

  • Выполняется на том же уровне, что и JavaScript: JS Engine, как Chrome V8.
  • И JavaScript все еще может управлять различными веб-API

В то же время WASM также может работать в Node.js или другой среде выполнения WASM.

Текстовый формат WebAssembly

На самом деле WASM представляет собой набор двоичных форматов, которые могут выполняться напрямую, но для удобства отображения в текстовых редакторах или инструментах разработчика WASM также разрабатывает «промежуточный» формат.текстовый формат.``watили.wastНазовите расширение, затем передайтеwabtи другие инструменты для преобразования WASM в текстовом формате в исполняемый код в двоичном формате для.wasmв расширенном формате.

Давайте посмотрим на кусок кода модуля в текстовом формате WASM:

(module
  (func $i (import "imports" "imported_func") (param i32))
  (func (export "exported_func")
    i32.const 42
    call $i
  )
)

Логика приведенного выше кода следующая:

  • Сначала определите модуль WASM, затем начните сimportsМодуль JS импортирует функциюimported_func, назови это$i, получить параметрыi32
  • Затем экспортируйте файл с именемexported_funcфункцию, вы можете импортировать эту функцию из веб-приложения, например JS, для использования
  • Тогда параметрыi32Передайте 42, затем вызовите функцию$i

Мы включаем вышеуказанный текстовый формат в двоичный код через WABT:

  • Скопируйте приведенный выше код во вновь созданный файл с именемsimple.watсохранено в файле
  • использоватьwabtСкомпилируйте и конвертируйте

После того, как вы установили wabt, выполните следующую команду для компиляции:

wat2wasm simple.wat -o simple.wasm

Хотя он преобразован в двоичный, его содержимое нельзя просмотреть в текстовом редакторе.Чтобы просмотреть двоичное содержимое, мы можем добавить-vВариант вывода содержимого командной строки:

wat2wasm simple.wat -v

Результат выглядит следующим образом:

Видно, что WebAssembly на самом деле является кодом в двоичном формате, и даже если он предоставляет немного читаемый текстовый формат, его сложно использовать для фактического кодирования, не говоря уже об эффективности разработки.

Попытка WebAssembly как языка программирования

Поскольку приведенные выше двоичные и текстовые форматы не подходят для кодирования, они не подходят для WASM в качестве обычного языка разработки.

Чтобы обойти это ограничение,AssemblyScriptВыйдя на первый план, AssemblyScript — это вариант TypeScript, который добавляетТип веб-сборки ,можно использоватьBinaryenСкомпилируйте его в WebAssembly.

Типы WebAssembly примерно следующие:

  • i32, u32, i64, v128 и т. д.
  • Небольшие целочисленные типы: i8, u8 и т. д.
  • Целочисленный тип переменной: isize, usize и т. д.

Binaryen статически компилирует AssemblyScript в строго типизированный двоичный файл WebAssembly, прежде чем передать его механизму JS для выполнения.Поэтому, хотя AssemblyScript обеспечивает уровень абстракции, фактический код, используемый для производства, по-прежнему является WebAssembly, что сохраняет преимущество WebAssembly в производительности. AssemblyScript очень похож на TypeScript, предоставляя набор встроенных функций для прямого управления функциями WebAssembly и компилятора.

Встроенные функции:

  • Проверка статического типа:

    • function isInteger<T>(value?: T): ``boolЖдать
  • Вспомогательные функции:

    • function sizeof<T>(): usizeЖдать
  • Управление WebAssembly:

    • Математические операции

      • function clz<T>(value: T): TЖдать
    • операция памяти

      • function load<T>(ptr: usize, immOffset?: usize): TЖдать
    • поток управления

      • function select<T>(ifTrue: T, ifFalse: T, condition: ``bool``): TЖдать
    • SIMD

    • Atomics

    • Inline instructions

Затем создайте стандартную библиотеку на основе этого набора встроенных функций.

Стандартная библиотека:

  • Globals
  • Array
  • ArrayBuffer
  • DataView
  • Date
  • Error
  • Map
  • Math
  • Number
  • Set
  • String
  • Symbol
  • TypedArray

Например, типичный массив используется следующим образом:

var arr = new Array<string>(10)

// arr[0]; // 会出错 😢

// 进行初始化
for (let i = 0; i < arr.length; ++i) {
  arr[i] = ""
}
arr[0]; // 可以正确工作 😊

Видно, что AssemblyScript добавляет синтаксис, аналогичный TypeScript, в JavaScript, а затем ему необходимо поддерживать требования статической строгой типизации, такой как используемый C/C++.Если он не инициализирован, при выделении памяти будет сообщено об ошибке выполняется.

Есть также некоторые библиотеки расширений, такие как процесс Node.js, крипто и т. д., консоль JS и некоторые StaticArray, куча и т. д., связанные с памятью.

Можно видеть, что с помощью вышеуказанных базовых типов, встроенных библиотек, стандартных библиотек и библиотек расширений, AssemblyScript в основном создает все функции, которые есть у JavaScript.В то же время, AssemblyScript предоставляет синтаксис, аналогичный TypeScript, и строго следует строгому типизированный статический язык в письменной форме спецификация.

Стоит отметить, что, поскольку текущая спецификация модуля ES для WebAssembly все еще находится в черновике, AssemblyScript реализует модуль сам по себе, например экспорт модуля:

// env.ts
export declare function doSomething(foo: i32): void { /* ... 函数体 */ }

Импортируйте модуль:

import { doSomething } from "./env";

Пример большого фрагмента кода с использованием классов:

class Animal<T> {
  static ONE: i32 = 1;
  static add(a: i32, b: i32): i32 { return a + b + Animal.ONE; }

  two: i16 = 2; // 6   instanceSub<T>(a: T, b: T): T { return a - b + <T>Animal.ONE; } // tsc does not allow this }

export function staticOne(): i32 {
  return Animal.ONE;
}

export function staticAdd(a: i32, b: i32): i32 {
  return Animal.add(a, b);
}

export function instanceTwo(): i32 {
  let animal = new Animal<i32>();
  return animal.two;
}

export function instanceSub(a: f32, b: f32): f32 {
  let animal = new Animal<f32>();
  return animal.instanceSub<f32>(a, b);
}

AssemblyScript открыл для нас новую дверь. Он может использовать синтаксис в стиле TS и следовать статическим спецификациям строгого типа для эффективного кодирования, и в то же время он может легко работать с API, связанными с WebAssembly/компилятором. может быть скомпилирован Binaryen.Компилятор компилирует его в двоичный файл WASM, а затем получает производительность выполнения WASM.

Благодаря гибкости и производительности ассемблера, экосистема приложений, построенных с помощью ассемблера, начала процветать.Существует большое количество продуктов, созданных с помощью ассемблера, с точки зрения:Woohoo Сборка script.org/built-with-…

Выше показана игра в нарды, созданная с использованием AssemblyScript.

Гениальная философия: запускайте код C/C++ в браузере

Хотя появление AssemblyScript значительно улучшило недостатки WebAssembly в плане эффективного кодирования, в качестве нового языка программирования его самым большим недостатком является экология, разработчики и накопление.

Разработчики WebAssembly, очевидно, учли различные идеальные условия при разработке. Поскольку WebAssembly является двоичным форматом, его можно использовать в качестве цели компиляции для других языков. Если компилятор можно построить, он может преобразовать существующий, Если зрелый язык с большое количество разработчиков и сильная экосистема скомпилированы в WebAssembly для использования, то это эквивалентно прямому повторному использованию накопленного за многие годы этого языка, и использованию их для улучшения экосистемы WebAssembly и запуска их в Web и Node.js middle .

К счастью, для C / C ++ уже естьEmscriptenТакие отличные компиляторы существуют.

Положение Emscripten в цепочке разработки можно интуитивно объяснить с помощью следующей картинки:

То есть скомпилировать код C/C++ (или Rust/Go и т. д.) в WASM, а затем запустить WASM в среде выполнения браузера (или Node.js) с помощью связующего кода JS, такого как ffmpeg, который использует C для записи аудио и инструменты транскодирования видео. Его можно скомпилировать в Интернет с помощью компилятора Emscripten, а аудио и видео можно транскодировать непосредственно в интерфейсе браузера.

Приведенный выше код JS "Gule" необходим, потому что, если вам нужно скомпилировать C/C++ в WASM и выполнить его в браузере, вы должны реализовать веб-API, который сопоставляется с операциями, связанными с C/C++, чтобы обеспечить эффективное выполнение, Эти связующие коды в настоящее время включают в себя некоторые из наиболее популярных библиотек C/C++, такие какSDL,OpenGL,OpenAL,так же какPOSIXчасть API.

В настоящее время самый большой сценарий использования WebAssembly — это способ компиляции модулей C/C++ в WASM.Наиболее известные примеры:Unreal Engine 4,Unityтаких как большие библиотеки или приложения.

Заменит ли WebAssembly JavaScript?

Ответ - нет.

Фактически, в соответствии с приведенными выше уровнями объяснения, первоначальный дизайн WASM можно разделить на следующие пункты:

  • В максимально возможной степени повторно использовать существующую базовую языковую экологию, например накопление C/C++ в разработке игр, проектировании компиляторов и т. д.
  • Получите почти нативную производительность в Интернете, Node.js или других средах выполнения WASM, то есть браузеры также могут запускать крупномасштабные игры, редактирование изображений и другие приложения.
  • Существует также наибольшая степень совместимости с Интернетом, обеспечивающая безопасность
  • Также в разработке (если вам нужно разрабатывать) легко читать и писать и отлаживаться, что в AssemblyScript идет дальше

Так что из первоначального замысла на роль WebAssembly больше подходит следующая картинка:

WASM соединяет экологию различных языков системного программирования и дополнительно дополняет экологию веб-разработки, а также обеспечивает повышение производительности для JS, который является важной частью территории, отсутствовавшей при разработке Интернета.

Веб-фреймворк Rust:GitHub.com/ также для стека/ также…

Глубокое погружение в Emscripten

адрес:GitHub.com/em скрипт en-…

Все следующие демо доступны в репозитории:code.No special.org/Huang Wei. Счет-фактура...оказаться

Звезда: 21,4K

Техническое обслуживание: активно

Emscripten — это набор инструментов кроссплатформенного компилятора с открытым исходным кодом для компиляции C/C++ в WebAssembly, состоящий из LLVM, Binaryen, Closure Compiler и других инструментов.

Основным инструментом Emscripten является Emscripten Compiler Frontend (emcc), который используется для замены некоторых собственных компиляторов, таких как gcc или clang, для компиляции кода C/C++.

Фактически, для того, чтобы почти все переносимые кодовые базы C/C++ можно было скомпилировать в WebAssembly и выполнить в Интернете или на Node.js, Emscripten Runtime фактически обеспечивает совместимость со стандартными библиотеками C/C++ и связанными API для Web/Node.js. Сопоставление API, это сопоставление существует в скомпилированном коде клея JS.

Посмотрите на рисунок ниже: красная часть — это скомпилированный продукт Emscripten, а зеленая часть — некоторая поддержка во время выполнения, которую Emscripten предоставляет для обеспечения возможности выполнения кода C/C++:

Простой опыт «Hello World»

Стоит отметить, что установка наборов инструментов, связанных с WebAssembly, почти всегда предоставляется в виде исходного кода, что может быть связано с привычками экосистемы C/C++.

Чтобы завершить простую программу C/C++, работающую в Интернете, нам сначала нужно установить Emscripten SDK:

# Clone 代码仓库
git clone https: // github . com / emscripten-core / emsdk . git

# 进入仓库
cd emsdk

# 获取最新代码,如果是新 clone 的这一步可以不需要
git pull

# 安装 SDK 工具,我们安装 1.39.18,方便测试
./emsdk install 1.39.18

# 激活 SDK
./emsdk activate 1.39.18

# 将相应的环境变量加入到系统 PATH
source ./emsdk_env.sh

# 运行命令测试是否安装成功
emcc -v #

Если установка прошла успешно, приведенная выше команда выдаст следующие результаты после запуска:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.39.18
clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 613c4a87ba9bb39d1927402f4dd4c1ef1f9a02f7)
Target: x86_64-apple-darwin21.1.0
Thread model: posix

Подготовим исходный код:

mkdir -r webassembly/hello_world
cd webassembly/hello_world && touch main.c

существуетmain.cДобавьте следующий код в:

 #include <stdio.h>
int main() {
  printf("hello, world!\n");
  return 0;
}

Затем используйте EMCC, чтобы скомпилировать этот C-код, переключитесь в командную строкуwebassembly/hello_worldкаталог, запустите:

emcc main.c

Приведенная выше команда выведет два файла:a.out.jsа такжеa.out.wasm, последний представляет собой скомпилированный код wasm, а первый — связующий код JS, который обеспечивает среду выполнения для запуска WASM.

Быстрый тест можно выполнить с помощью Node.js:

node a.out.js

будет выводить"hello, world!", мы успешно запускаем код C/C++ в среде Node.js.

Далее попробуем запустить код в веб-среде и изменить скомпилированный код следующим образом:

emcc main.c -o main.html

Приведенная выше команда создаст три файла:

  • main.jsклей код
  • main.wasmWASM-код
  • main.htmlЗагрузите связующий код и выполните некоторую логику WASM.

Для Emscripten существуют определенные правила генерации кода.Подробнее см.:em script en.org/docs/com bulk…

Если вы хотите открыть этот HTML-код в браузере, вам нужно запустить сервер локально, потому что просто открыть его черезfile://Во время доступа по протоколу основные браузеры не поддерживают запросы XHR, а запросы XHR могут выполняться только под HTTP-сервером, поэтому мы запускаем следующую команду, чтобы открыть веб-сайт:

npx serve .

открыть страницу, посетитьlocalhost:3000/main.html, вы можете увидеть следующие результаты:

При этом в инструментах разработчика будут соответствующие распечатки:

Мы успешно запустили код C в Node.js и браузере!

О будущем WebAssembly

В этой статье перечислены только некоторые из текущих основных сценариев приложений WebAssembly, включая высокую производительность, малый вес и кросс-платформенность WebAssembly, что позволяет нам запускать такие языки, как C/C++, в Интернете и настольные приложения в Интернете. Веб-контейнер.

Но чего эта статья не касается, так этоWASI, стандартизированный системный интерфейс для запуска WebAssembly в любой системе. Когда производительность WebAssembly будет постепенно повышаться, WASI может предоставить реальный способ запуска любого кода на любой платформе, точно так же, как это делает Docker, но не должен ограничиваться операционной системой. . Как сказал основатель Docker:

«Если бы WASM+WASI существовали в 2008 году, не было бы необходимости создавать Docker, WASM на сервере — это будущее вычислений, долгожданный стандартизированный системный интерфейс.

Еще одним интересным контентом является среда разработки WASM на стороне клиента, такая какyew, в будущем может стать таким же популярным, как React/Vue/Angular.

И инструмент управления пакетами WASMWAPM, благодаря кроссплатформенному характеру WASM, может стать предпочтительным способом обмена пакетами между различными платформами на разных языках.

В то же время, WebAssembly также является проектом, в основном разработанным W3C, спонсируемым и совместно поддерживаемым крупными производителями, включая Microsoft, Google, Mozilla и т. д. Я верю, что у WebAssembly очень многообещающее будущее.

Ссылка на ссылку

❤️/Спасибо за поддержку/

Выше приведено все содержание этого обмена, я надеюсь, что это поможет вам ^_^

Если вам понравилось, не забудьте поделиться, поставить лайк и добавить в избранное~

Добро пожаловать в публичный аккаунтавтобус программиста, три брата из Byte, Shopee и Zhaoyin, делятся опытом программирования, техническими галантерейными товарами и планированием карьеры, чтобы помочь вам избежать окольных путей, чтобы попасть на большую фабрику.