Демо WebAssembly

1. Что?


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

Портативный, небольшой и быстро загружаемый (двоичный) формат, подходящий для компиляции в Интернет.

Основная цель - поддержка высокопроизводительных приложений в веб-среде. Но дизайн не зависит от веб-функций и не предоставляет функций для веб-функций, а также может использоваться в других средах.

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

Цели дизайна делятся на 2 аспекта:

Быстрая, безопасная и переносимая семантика

Быстро: выполнение с производительностью, близкой к собственному коду, и использование функций, общих для всего современного оборудования.

Безопасность: код проверяется и выполняется в безопасной для памяти изолированной среде, чтобы предотвратить повреждение данных или нарушения безопасности.

Четкое определение: полное и точное определение юридических процедур и их поведения таким образом, чтобы его можно было легко сделать неформальным и формальным

Независимость от оборудования: компилируйте для всех современных архитектур, настольных или мобильных устройств, а также встроенных систем.

Независимость от языка: отсутствие предвзятого отношения к какому-либо конкретному языку, модели программирования или объектной модели

Независимость от платформы: может быть встроена в браузер, работать как автономная виртуальная машина или интегрирована в другие среды.

Открытый: Программы могут взаимодействовать со своей средой простым и универсальным способом.

Эффективное и портативное представление

Маленький и изысканный: двоичный формат меньше, чем типичный текстовый формат или формат собственного кода, и может быть быстро передан

Модульность: программу можно разделить на более мелкие части, которые можно передавать, кэшировать и использовать отдельно.

Эффективность: его можно декодировать, проверять и быстро компилировать за один проход (обход), что эквивалентно компиляции в реальном времени (JIT) или заблаговременной (AOT) компиляции.

Потоковая передача: позволяет начать декодирование, проверку и компиляцию как можно раньше, прежде чем все данные станут доступны

Параллельный: позволяет разделить декодирование, проверку и компиляцию на несколько независимых параллельных задач.

Переносимость: никаких предположений об архитектурах, которые не широко поддерживаются современным оборудованием.

Основные браузеры (Chrome, Edge, Firefox и WebKit) совместно продвигают процесс стандартизации:


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

PS Этим руководят производители браузеров (четверо из них объединяются, чтобы делать что-то, этого стоит с нетерпением ждать), просто между прочим, открытые стандарты (не только для веб-среды), мотивация исходит из желания еще больше улучшить производительность времени выполнения JS в V8 После внедрения JIT дальнейшее улучшение производительности невозможно из-за ограничений функций языка JS (таких как интерпретируемые и слабые типы). Веб-возможности становятся все сильнее и сильнее, клиентский JS становится все тяжелее и тяжелее, а потребность в дальнейшем улучшении производительности выполнения JS все еще существует, поэтому есть чистая прибыль WebAssembly.

2. Wasm и wast
Мы знаем, что WebAssembly определяет двоичный формат, это формат wasm, например:


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 

Код C, соответствующий этой строке шестнадцатеричных чисел:


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

Читаемость wasm равна 0. Чтобы решить эту проблему, определен текстовый формат с лучшей читабельностью, который называется 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)
 )
)

Скобки немного в стиле Лиспа, но, по крайней мере, они читабельны, например:

// 导出了两个东西,分别叫`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 и wasm могут быть преобразованы друг в друга, подробности см. В WABT: The WebAssembly Binary Toolkit.

Кроме того, вы можете увидеть еще одну текстовую команду на панели «Источник» браузера:


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

Выглядит очень похоже на wast, не знаю, есть ли название, или оно тоже принадлежит wast? Преобразуется браузером на основе wasm.

3. Экологические
требования к среде проведения пробных игр :

Среда компиляции C / C ++ Emscripten

Браузер, поддерживающий WebAssembly (последняя версия Chrome поддерживает его по умолчанию)


Вредит ли онлайн-среда ? Демо-среда: WebAssembly Explorer

КОМПИЛИРОВАТЬ и ЗАГРУЗИТЬ можно получить wasm, им легко пользоваться

Обратите внимание, что по умолчанию используется среда C ++. Если вы хотите использовать C, выберите C99 или C89 слева, иначе имя функции будет повреждено, например, потеря 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)
 )
)

Имя функции было скомпилировано в _Z3gcdii. Предполагается, что что-то вроде пространства имен вызывает проблемы. Я не знаком с C ++. Используйте C послушно.

PS Помимо C / C ++, другие языки также могут воспроизводить WebAssembly, например Rust


Скачать SDK платформы для локальной среды

Следуйте инструкциям по установке

Если ничего другого, вы можете установить его здесь, вы можете попробовать 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)

В среде Windows вы можете столкнуться с ошибкой отсутствия библиотеки DLL (MSVCP140.dll). Вы можете вручную установить требуемую среду C ++. Подробнее см. MSVCP140.dll not found · Проблема № 5605 · kripken / emscripten

Затем вы можете попробовать (сохраните предыдущий код C как файл gcd.c):

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

PS Для получения дополнительной информации см. Учебник Emscripten.

Содержимое gcd.wasm выглядит следующим образом:


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 

Обратите внимание, что по умолчанию перед именем метода будет стоять знак подчеркивания (_). В этом примере имя экспортируемого метода - _gcd. Подробнее см. В разделе «Взаимодействие с кодом»:


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.

Интерфейс модуля, используемый в JS, должен быть подчеркнут (я не знаю, есть ли элемент конфигурации, который может его удалить)

Четыре. Попробуйте


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));
});

Шестнадцатеричная строка взята из онлайн-демонстрации, которая согласуется с исходным примером wasm. Просто вставьте эти вещи в консоль Chrome для выполнения. Если все в порядке, вы получите сообщение об ошибке:


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

Это связано с тем, что ограничения CSP (политики безопасности контента) по умолчанию легко решить, просто включите режим инкогнито (Ctrl / CMD + Shift + N)

Получим вывод:


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

Первая строка - это содержимое экспорта модуля, полученное путем загрузки нашей WebAssembly, включая объект памяти и метод gcd, а выходные данные второй строки - это наибольший общий делитель, вычисленный путем вызова высокопроизводительного модуля.

WebAssembly.compile и другие связанные API могут ссылаться на:

JavaScript API-WebAssembly: определение спецификации

WebAssembly-JavaScript | MDN: содержит примеры

Кроме того, для локально скомпилированной версии требуется импорт env (и имя функции имеет префикс подчеркивания _):


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));
});

Вы можете получить аналогичный результат:


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

Должно быть, Emscripten по умолчанию добавил некоторые нерелевантные вещи, которые функционально эквивалентны нашей упрощенной версии.

V.
Преимущества, недостатки и сценарии применения.
Небольшой размер кода.

Около 300к (сжатой) логики JavaScript переписано с помощью WebAssembly, объем всего около 90к

Но использование WebAssembly требует внедрения библиотеки классов JavaScript размером 50-100 тысяч в качестве инфраструктуры.

Безопасность немного улучшена

Хотя текстовые инструкции WebAssembly, соответствующие исходному коду, по-прежнему не скрыты, обратная стоимость выше.

Улучшение производительности

Теоретически WebAssembly имеет производительность, близкую к исходной, поскольку пропускает процесс интерпретации, а размер файла также имеет преимущества с точки зрения передачи.

Конечно, предпосылка состоит в том, что в сценариях, где объем бизнес-кода велик и требуется экстремальная производительность, в сценариях повторного выполнения, таких как тесты производительности, JIT не намного медленнее, чем AOT.

Недостатки на
данный момент ограниченные возможности:

Поддерживаются только несколько основных типов данных (i32 / i64 / f32 / f64 / i8 / i16)

Нет прямого доступа к DOM и другим веб-API

Невозможно управлять сборщиком мусора

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

Прежде всего, первоначальная цель WebAssembly - «поддерживать высокопроизводительные приложения в веб-среде». Чтобы преодолеть узкое место в производительности, возможны следующие сценарии приложений:

Декодирование видео

Обработка изображения

3D / WebVR / AR визуализация

Механизм рендеринга

Физический движок

Алгоритм сжатия / шифрования

… И т. Д. Сцены с большим количеством вычислений

Конечно, в будущем в браузер может быть встроена некоторая поддержка вместо использования «расширений» и т.п. Но реальное значение WebAssembly состоит в том, чтобы обеспечить возможность саморасширения высокопроизводительных «собственных» модулей. В конце концов, может потребоваться много времени, чтобы ждать, пока браузер предоставит его, и ждать, пока совместимость станет приемлемой. Благодаря этой возможности, Не нужно ждать, пока основные браузеры на рынке поддержат определенную встроенную функцию, вы можете сделать это самостоятельно, и разницы в совместимости нет. И наоборот, может появиться ряд популярных модулей сообщества, которые постепенно будут приняты в качестве встроенной поддержки браузера, экологично вернув веб-среде.

Ссылка
WebAssembly

WebAssembly на практике: как писать код: отличное руководство

Как прокомментировать новейшую технологию байт-кода WebAssembly в браузерах?

WebAssembly: серебряная пуля для решения хронических проблем JavaScript?

WebAssembly, новая эра Интернета

Можно ли использовать WebAssembly с полифилом?

wasm-array: библиотека упаковки массивов WebAssembly

рекомендация

отblog.51cto.com/15080030/2592698