Основы WebAssembly
В этой статье объясняются концепции, лежащие в основе работы технологии WebAssembly, включая её цели, проблемы, которые она решает, и то, как она работает в движке рендеринга веб-браузера.
Что такое WebAssembly?
WebAssembly — это технология, предоставляющая новый тип кода, который можно запускать в современных веб-браузерах, что обеспечивает новые функции и значительное повышение производительности. Код для WebAssembly не предназначен для написания вручную, скорее он спроектирован для эффективной компиляции из низкоуровневых исходных языков, таких как C, C++, Rust и.т.д.
WebAssembly позволяет запускать код, написанный на различных языках в web-приложениях почти c естественной скоростью. Это имеет огромное значение для веб-платформы, так как ранее это нельзя было сделать.
Более того, вам даже не нужно знать, как создавать код WebAssembly, чтобы его использовать. Модули WebAssembly можно импортировать в веб-приложение (или Node.js), и экспортировать из них функции для использования через JavaScript. JavaScript-фреймворки могут использовать модули WebAssembly для получения огромных преимуществ в производительности и новых функций, в то же время делая их функциональность легко доступной для веб-разработчиков.
Цели WebAssembly
Технология WebAssembly создаётся как открытый стандарт внутри W3C WebAssembly Community Group со следующими целями:
- Быть быстрым, эффективным и переносимым — код WebAssembly может выполняться практически на естественной скорости на разных платформах, используя преимущества аппаратных возможностей.
- Быть читаемым и отлаживаемым — WebAssembly — это низкоуровневый ассемблерный язык, но он имеет читабельный текстовый формат (спецификация для которого ещё дорабатывается), который позволяет писать, просматривать и отлаживать код вручную.
- Поддерживать безопасность — код WebAssembly предназначен для запуска в безопасной, изолированной среде выполнения. Как и другой веб-код, он будет соблюдать политики безопасности браузера.
- Не разрушать текущий веб — технология WebAssembly разработана так, что она прекрасно сочетается с другими веб-технологиями и поддерживает обратную совместимость.
Примечание: Технология WebAssembly также будет иметь возможность использования за пределами веб и JavaScript-сред (см. Встраивание вне Web).
Как WebAssembly встраивается в веб-платформу?
Веб-платформа может рассматриваться как состоящая из двух частей:
- Виртуальная машина (ВМ), на которой выполняется код веб-приложения, например код JavaScript, который обеспечивает работу ваших приложений.
- Набор Web API, которые веб-приложение может вызывать для управления функциональными возможностями веб-браузера / устройства и выполнения задач (DOM, CSSOM, WebGL, IndexedDB, Web Audio API, и т.д.)
Исторически ВМ могла загружать только JavaScript. Раньше нас это вполне устраивало, поскольку JavaScript достаточно мощный, чтобы решать большинство проблем, с которыми мы сталкивались в интернете. Однако мы столкнулись с проблемами производительности, когда попытались использовать JavaScript для более нагруженных сценариев использования, таких как 3D-игры, виртуальная и дополненная реальность, компьютерное зрение, редактирование изображений / видео и в ряде других применений, которые требуют повышенной производительности (см. варианты использования WebAssembly где описано больше идей).
Кроме того, длительность загрузки, анализа и компиляции очень больших приложений JavaScript может быть непомерно высокой. Мобильные и другие ограниченные в ресурсах платформы могут ещё более понизить производительность.
Язык WebAssembly отличается от языка JavaScript, но он не предназначен для его замены. Он предназначен для дополнения и работы вместе с JavaScript, что позволяет веб-разработчикам использовать преимущества обоих языков:
- JavaScript — это язык высокого уровня, гибкий и достаточно выразительный для написания веб-приложений. Он имеет много преимуществ — он динамически типизирован, не требует этапа компиляции и обладает огромной экосистемой, которая предоставляет мощные фреймворки, библиотеки и другие инструменты.
- WebAssembly — это низкоуровневый язык, похожий на ассемблер, с компактным двоичным форматом, который работает с почти естественной производительностью и предоставляет низкоуровневые модели памяти для таких языков как C++ и Rust, с целью компиляции, чтобы они могли работать в интернете. (Обратите внимание, что у WebAssembly на будущее есть высокоуровневая цель по поддержке языков со сборщиками мусора в модели памяти).
С появлением WebAssembly в браузерах виртуальная машина, о которой мы говорили ранее, теперь будет загружать и запускать два типа кода — JavaScript и WebAssembly.
Различные типы кода могут вызывать друг друга по мере необходимости — WebAssembly JavaScript API оборачивает экспортированный код WebAssembly в функции JavaScript, которые можно вызывать обычным способом. А в код WebAssembly можно импортировать и синхронно вызывать обычные функции JavaScript. Фактически, базовая единица кода WebAssembly называется модулем, а модули WebAssembly во многом схожи с модулями ES2015.
Ключевые понятия WebAssembly
Есть несколько ключевых понятий, необходимых для понимания того, как WebAssembly работает в браузере. Все эти понятия отражены 1:1 в WebAssembly JavaScript API.
- Модуль: Представляет двоичный файл WebAssembly, который был скомпилирован браузером в исполняемый машинный код. Модуль не имеет состояния и, таким образом, как Blob, может быть явным образом разделён между windows и workers (через postMessage() (en-US)). В модуле есть объявление импорта и экспорта точно такое же, как и в модуле ES2015.
- Память: Массив ArrayBuffer изменяемого размера, который содержит линейный массив байтов, считываемых и записываемых инструкциями низкоуровневого доступа к памяти в WebAssembly.
- Таблица: Типизированный массив ссылок изменяемого размера (например, для функций), которые не могут быть размещены в памяти в виде байтов (по соображениям безопасности и переносимости).
- Экземпляр: Модуль в паре со своим состоянием, которое он использует во время выполнения, включая память, таблицу и набор импортируемых значений. Экземпляр модуля похож на модуль ES2015, который был загружен в определённую глобальную переменную с определённым набором импортов.
JavaScript API предоставляет разработчикам возможность создавать модули, объекты памяти, таблицы и экземпляры модулей. Получив экземпляр модуля WebAssembly, код JavaScript может синхронно вызывать его экспорты, которые представляются как обычные функции JavaScript. Любые функции JavaScript также могут синхронно вызываться кодом WebAssembly путём передачи этих функций в качестве импорта в экземпляр модуля WebAssembly.
Поскольку JavaScript полностью контролирует загрузку, компиляцию и запуск кода WebAssembly, разработчики JavaScript могут рассматривать технологию WebAssembly как расширение JavaScript для эффективной генерации высокопроизводительных функций.
В будущем модули WebAssembly будут загружаться так же, как и модули ES2015 (с использованием ), что означает, что JavaScript сможет извлекать, компилировать и импортировать модуль WebAssembly так же легко, как модуль ES2015.
Как я могу использовать WebAssembly в своём приложении?
Выше мы говорили о низкоуровневых примитивах, которые WebAssembly добавляет к веб-платформе: двоичный формат для кода и API для его загрузки и запуска. Теперь давайте поговорим о том, как мы можем использовать эти примитивы на практике.
Экосистема WebAssembly находится на начальной стадии; больше инструментов, несомненно, появится в будущем. На данный момент есть три основные отправные точки:
- Портирование приложения C/C++ с Emscripten.
- Написание или генерация WebAssembly кода непосредственно на уровне сборки.
- Написание приложения Rust и выбор WebAssembly в качестве типа вывода при построении.
Давайте поговорим об этих вариантах:
Портирование из C/C++
Из множества вариантов создания кода WASM есть два наиболее популярных — это онлайн-сборщик wasm или Emscripten. Существует ещё несколько вариантов сборки WASM, таких как:
Это отличные ресурсы для людей, которые хотят начать, но у них нет инструментов и возможностей Emscripten.
Инструмент Emscripten способен взять практически любой исходный код C/C++ и скомпилировать его в модуль .wasm, добавив необходимый «связующий» JavaScript-код для загрузки и запуска модуля в HTML-документе и отображения результатов работы.
В двух словах, процесс работает следующим образом:
- Сначала Emscripten передаёт код C/C++ в clang + LLVM — набор инструментов компилятора C/C++ с открытым исходным кодом, который поставляется, например, как часть XCode для OSX.
- Emscripten преобразует скомпилированный результат clang + LLVM в двоичный файл .wasm.
- Сам по себе код WebAssembly в настоящее время не может напрямую обращаться к DOM; он может вызывать только JavaScript, передавая целочисленные и числа с плавающей точкой примитивные типы данных. Таким образом, чтобы получить доступ к любому Web-API, WebAssembly модуль должен обращаться к JavaScript, который затем вызывает Web-API. Поэтому Emscripten создаёт необходимый для этого связующий код HTML и JavaScript.
Связующий код JavaScript не так прост, как вы можете себе представить. Прежде всего Emscripten предоставляет популярные библиотеки C/C++, такие как SDL, OpenGL, OpenAL и части POSIX. Эти библиотеки реализованы с точки зрения Web-API, и поэтому каждой из них требуется некоторый код JavaScript для соединения WebAssembly модуля с базовым Web-API.
Таким образом, часть связующего кода предоставляет функциональность каждой библиотеки, используемой кодом C/C++. Связующий код также содержит логику для вызова вышеупомянутых WebAssembly JavaScript API для извлечения, загрузки и запуска файла .wasm.
Сгенерированный HTML-документ загружает связующий файл JavaScript и может записать stdout в (en-US). Если приложение использует OpenGL, HTML документ будет содержать элемент , который будет использоваться для рендеринга. Очень легко изменить тип вывода компиляции Emscripten на любое веб-приложение, которое вам нужно.
Вы можете найти полную документацию по Emscripten на emscripten.org, а также руководство по созданию набора инструментов и компиляции вашего собственного приложения на C/C++ в wasm в разделе Компилирование из C/C++ в WebAssembly.
Написание WebAssembly напрямую
Хотите создать свой собственный компилятор, собственные инструменты или библиотеку JavaScript, которая генерирует WebAssembly во время выполнения?
Аналогично другим ассемблерным языкам, двоичный формат WebAssembly имеет текстовое представление с которым имеет соответствие 1:1. Вы можете написать или сгенерировать этот формат вручную, а затем преобразовать его в двоичный формат с помощью любого из инструментов преобразования текста в двоичные файлы WebAssembly.
Простое руководство о том, как это сделать, смотрите в нашей статье Перевод из текстового формата WebAssembly в wasm.
Написание приложения Rust с компиляцией в WebAssembly
Благодаря неустанной работе рабочей группы Rust WebAssembly, стало возможно писать Rust код и компилировать его в WebAssembly. В нашей статье Компиляция из Rust в WebAssembly описан процесс установки необходимого набора инструментов, компиляция примера программы Rust в пакет npm для WebAssembly с целью использования его в качестве примера веб-приложения.
Резюме
Эта статья дала вам объяснение того, что такое технология WebAssembly, чем она полезная, как она вписывается в веб и как вы можете её использовать.
Смотрите также
- Статьи WebAssembly в блоге Mozilla Hacks
- WebAssembly на Mozilla Research
- Загрузка и запуск кода WebAssembly — узнайте, как загрузить свой собственный модуль WebAssembly на веб-страницу.
- Использование WebAssembly JavaScript API — узнайте, как использовать другие основные функции WebAssembly JavaScript API.
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 3 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.
Введение в WebAssembly
WebAssembly ( Wasm ) предоставляет формат бинарных инструкций для виртуальной машины на основе стека. Проще говоря WebAssembly представляет технологию, которая позволяет запускать в браузере низкоуровневый скомпилированный код.
Предтечей появления Wasm была разработка в компании Google Native Client (NaCL) — специального инструмента, который позволял запускать нативный код на C/C++ в веб-браузере. Нативный код компилировался в файлы с расщирением nexe и запускался в песочнице браузера (sandbox), поэтому его выполнение было относительно безопасным. Однако технология была доступна только для приложений и плагинов из Google Chrome Web Store Далее был разработан Portable Native Client (PNaCL) . Если NaCL был платформенно-зависимым, то PNaCL, наоборот, не зависел от архитектуры и был теоретически доступен для всех приложений, а не только из Google Chrome Web Store. PNaCL состоял из двух компонентов: инструментария, который компилировал код C/C++ в модули NaCL, и компонентов выполнения, которые встраивались в браузер и позволяли запускать модули NaCL.
Параллельно Mozilla, начиная с 2013 года, разрабатывала библиотеку asm.js , которая должна была транслировать код C/C++ в JavaScript.
В апреле 2015 международный консорциум по разработке веб-стандарто World Wide Web Consortium (W3C) создает рабочую группу по разработке спецификации по WebAssembly. И в марте 2017 года новый стандарт был принят. Изначально реализация WebAssembly в браузерах во многом базировалась на asm.js, в то время как для переноса скомпилированных модулей использовалась концепция PNaCL. Спецификация по WebAssembly доступна по адресу https://www.w3.org/TR/wasm-core-1/. Кроме того, разнообразную информацию о Wasm можно найти на официальном сайте https://webassembly.org.
При этом важно понимать, что WebAssembly — это не новый язык, это лишь бинарный формат, в который можно компилировать программу на разных языках. Работать с WebAssembly довольно просто. Вначале пишется обычный код, который размещается в текстовом файле. Преимущественно применяются C и C++, но также можно использовать Rust и другие языки. Далее этот код компилируется в бинарный формат в файл с расширением .wasm . Затем специальный код JavaScript загружает скомпилированный модуль на веб-страницу и вызывает функции, которые определены в модуле wasm.
При этом WebAssembly не предназначен для замены JavaScript, а лишь призван дополнить и обогатить возможности данного языка. Более того без JavaScript мы не сможем получить доступ к коду wasm.
Где Wasm может применяться? WebAssembly предназначен прежде всего для таких задач, где важна производительность, например, обработка картинок, аудио и видео, игры, распознование изображений, виртуальная реальность. По ряду задач при переходе от JavaScript к WebAssembly наблюдался прирост в производительности почти в 20 раз.
WebAssembly не ограничен только браузером и также может использоваться для создания гибридных нативных приложений на мобильных устройствах или для вычислений в приложениях на стороне бекэнда.
Для работы с Wasm преимущественно используются C, C++ и Rust, однако могут использоваться и другие языки, для которых существует поддержка компиляции в модули Wasm (например, C#, Go). Собственно это еще одно из преимуществ Wasm, поскольку не все программисты могут значть JavaScript, однако теперь можно писать если не весь, то по крайней мере немалую часть кода для клиентской стороны без знания JavaScript.
В то же время WebAssembly не лишен ограничений, которые следует учитывать при проектировании приложений:
- Отсутствует сборщик мусора (Garbage Collector). Хотя, возможно, поддержка GC будет добавлена впоследствии.
- Через Wasm нельзя взаимодействовать напрямую с DOM, для этого следует использовать JavaScript.
- Не поддерживается в ряде браузеров, в основном старых (например, IE 11). Какие браузеры поддерживают Wasm, можно посмотреть на https://caniuse.com/#feat=wasm. В коде JavaScript мы можем проверить наличие объекта WebAssembly перед выполнением кода на Wasm:
if(«WebAssembly» in window) < console.log("Браузер поддерживает WebAssembly"); // операции с WebAssembly >else
Полезные инстументы для изучения и практики WebAssembly
WebAssembly Studio представляет среду разработки, которая дсотупна онлайн, где можно посоздавать простейшие примеры с помощью языков C и Rust.
WasmFiddle — еще одна фактически онлайн-среда разработки, которая позволяет скомпиллировать код C в Wasm и провести минимальные исследования.
WebAssembly Binary Toolkit предоставляет утилиты командной строки для взаимодействия с кодом wasm, например, поддерживает их трансляцию в исходный код на C. Однако он не поддерживает компиляцию из C/C++ в Wasm.
Emscripten — один из наиболее популярных инструментов для компиляции из C/C++ в wasm.
Что такое WebAssembly: революционная технология для веба и не только
Вы наверняка слышали, что WebAssembly очень быстрый. Но что это значит, и что это за технология в целом? Ответы на эти и другие вопросы в публикации.
- Эффективность
- Безопасность
- Низкоуровневый бинарный формат
- WebAssembly уничтожит JavaScript?
- Придётся ли компилировать JavaScript в Wasm?
- WebAssembly 1.0 aka MVP
- Как работать с WebAssembly
- Не Web, да и не ассемблер
- Заключение
Начать стоит с важного замечания. Заявления о высокой скорости и производительности WebAssembly (Wasm) или другой технологии не нужно воспринимать буквально. В них обычно идет речь об относительной скорости и производительности, то есть о скорости wasm по сравнению с чем-то. Держите это в уме.
WebAssembly — безопасный и эффективный низкоуровневый бинарный формат для веба. Давайте рассмотрим, что это значит.
Эффективность
Когда кто-то говорит о Wasm, как правило речь идёт о его потенциальной высокой производительности. Объясняют высокую производительность тем, что браузер компилирует Wasm в эффективный машинный код. Однако высокая производительность — не единственное объяснение эффективности WebAssembly.
Wasm изначально проектировался с учётом формата компактных бинарных файлов. Поэтому его можно быстро загружать. Но, что более важно, код Wasm может быть преобразован в машинный прямо во время загрузки. Это называется потоковой компиляцией.
До появления WebAssembly код, написанный на C++ или Rust, перед использованием в вебе приходилось компилировать в JavaScript. Современные виртуальные машины компилируют JavaScript в машинный код, но начать этот процесс, по сути, можно только тогда, когда весь JS-код будет загружен. WebAssembly, напротив, компилируется в машинный код по мере загрузки, что сильно влияет на скорость запуска кода на исполнение. Настолько сильно, что узким местом уже становится скорость загрузки данных по сети, особенно на мобильных устройствах.
Потоковая компиляция — это прекрасно. Но и здесь есть нюансы. Так что сама возможность компилирования кода в Wasm не всегда означает, что это непременно нужно делать. Не так уж и сложно написать такой JS-код, который будет компактнее по размеру, чем порция компилированного в Wasm кода на C++. Ведь коду на JS не нужно нести с собой машинерию для управления памятью или любые другие функции, предоставляемые самим браузером. То есть вам не придётся реализовывать Array или библиотеку для парсинга JSON . Эти возможности уже есть в среде исполнения JavaScript — в браузере.
Wasm, напротив, не имеет никакого особого представления о C++ (или любом другом языке). Поэтому среда исполнения Wasm не предоставляет стандартную библиотеку C++ и компилятору её приходится добавлять в каждый бинарный файл. Как минимум, должны быть включены используемые в коде части библиотеки.
Увы, такие подробности способны смутить иного читателя. Причина тому — необходимость понимания того, как на самом деле работают и JS, и C++ и насколько они разные. Но не отчаивайтесь! Вы можете не понимать всех тонкостей, и тем не менее применять Wasm с пользой.
Безопасность
Развитие Web напрямую влияет на эволюцию браузеров. Браузеры постоянно наращивают свои возможности, всегда при этом оставаясь гарантами безопасности от злонамеренных действий со стороны. WebAssembly также следует по этому пути.
Wasm выполняется в песочнице, как и JavaScript. Он не имеет доступа к операционной системе, но имеет доступ к тем же API, что и JS. Поэтому WebAssembly не может выполнять произвольные системные вызовы или читать внутреннюю память браузера. Чтобы получить доступ к файловой системе, Wasm должен использовать File API , как JavaScript.
Это может показаться серьёзным ограничением, но безопасность — важный фундамент, на котором должна стоять любая технология.
WebAssembly обеспечивает дополнительную безопасность для таких языков, как C и C++. Классический пример — переполнение буфера , которое используется для внедрения вредоносного кода. Сами принципы работы WebAssembly делают невозможным появление этого класса уязвимостей. Вы можете переполнить буфер, C++ даёт такую возможность. Но внедрить вредоносный код не получится из-за отсутствия исполняемой памяти.
Однако, не стоит думать, что WebAssembly защищает от любых классов уязвимостей. Злоумышленник не сможет произвести атаку с инъекцией кода напрямую, однако у него остаётся возможность перехватить управление потоком исполнения через атаку повторного использования кода (code reuse attack) с помощью непрямых вызовов (indirect calls). Например, переполнение буфера способно вызвать перезапись указателя на функцию, да так, что указатель станет ссылаться на другую функцию. Упомянутые атаки против кода на C++ возможны благодаря самой природе языка. Использование языков вроде Rust позволяет избежать многих уязвимостей, но не всех. Да и для JavaScript существуют свои атаки подобного рода. Они есть и в других языках программирования, включая JavaScript.
Низкоуровневый бинарный формат
WebAssembly создавался в первую очередь как цель для компиляции, а не как язык, на котором будут писать вручную, хоть это и возможно. В основном вы будете писать код на более человекочитаемых языках, вроде C++ и Rust, и лишь затем компилировать ваш код в код машиночитаемый, который ещё называют «байт-кодом» (bytecode).
Пример кода C/C++, скомпилированного в байт-код
Байт-код похож на нативный машинный код, который использует ваш компьютер. Однако байт-код создан для виртуальной, а не реальной машины. Это делает код достаточно низкоуровневым, чтобы можно было производить оптимизации, но всё ещё портируемом, что позволяет не думать об архитектуре процессора (x64, ARM, и т.п.) на стороне конечного пользователя. Веб-браузеры имеют встроенные виртуальные машины для выполнения WebAssembly. Но вот ведь в чём штука: WebAssembly применим не только для Web. Об этом ниже.
Возможно, вы знакомы с другими форматами байт-кода, например, .Net CIL (CLR) или Java Bytecode (JVM). Вы могли бы подумать, почему разработчики не встроили в браузер один из этих (или других подобных) вариантов. Чтобы объяснить причину, придётся углубиться в технические нюансы, но здесь обойдёмся без этого. Достаточно понимать, что разные виртуальные машины имеют разные и часто несовместимые цели. Например, файлы Wasm могут быть верифицированы и скомпилированы виртуальной машиной на лету, что обеспечивает возможность потоковой компиляции. Другие форматы байт-кода не всегда обеспечивают такую возможность.
Существует множество других причин. Но даже если разработчики браузеров обеспечили бы поддержку одного из форматов байт-кода, вы не смогли бы исполнять существующие бинарные файлы как есть, так как в данном случае не соблюдается принцип безопасности: изоляция кода от операционной системы. Например, JVM имеет неограниченный доступ к файловой системе с помощью API типа java.io — запретной для веба технологии. Вместо этого разработчики WebAssembly выбрали путь исполнения в песочнице и использования существующих Web API.
WebAssembly уничтожит JavaScript?
Нет, JavaScript никуда не денется. Этот язык создан для того, чтобы на нём писали люди. Wasm создан для того, чтобы в него компилировался код, написанный людьми на C++, Rust и так далее. Фактически, по причине молодости WebAssembly на данный момент во многих случаях JavaScript всё ещё остаётся лучшим выбором для решения задач, связанных с веб. И при всех своих недостатках современный JS — отличный язык программирования.
Но никто не может предсказать будущее. WebAssembly не предназначен для того, чтобы уничтожить JavaScript. Но нельзя исключить, что в будущем какой-то язык программирования сможет конкурировать с JS в вебе благодаря компиляции в Wasm. Если это случится, скорее всего речь будет идти о новом языке типа Dart, Elm, Reason, созданном для веба.
Придётся ли компилировать JavaScript в Wasm?
JavaScript — предельно динамический язык. Только взгляните на этот забавный пример.
Если вы захотите скомпилировать произвольный JS-код в WebAssembly, например, библиотеку Lodash, вам придётся поставлять вместе с кодом ещё и солидную часть среды исполнения JavaScript. А чтобы достичь и той производительности, которая присуща браузерной реализации JS, вам придётся вместе с кодом поставлять среду исполнения практически целиком. Это непрактично из-за слишком большого размера файлов.
Поэтому компиляция JavaScript в Wasm в целом не очень хорошая идея. Но жёстко ограниченно подмножество JavaScript или аналогичный диалект могут быть быстрыми.
Например, Facebook использует оптимизатор JavaScript — Prepack. В целом этот проект не связан с Wasm. Но разработчики оптимизатора ищут способы безопасной статической компиляции некоторых паттернов кода JavaScript в WebAssembly. Пока неясно, насколько перспективны эти эксперименты.
Ещё один вариант — написание кода на языке, который похож на JavaScript, но не является им. AssemblyScript похож на TypeScript. Знакомые с JavaScript программисты могут использовать его, чтобы переписать критически важные для производительности компоненты JS-приложения.
AssemblyScript — многообещающая технология. Но она пока не подходит для создания приложений от начала до конца. Большая часть ограничений AssemblyScript связана с будущими возможностями Wasm. Важно не путать AssemblyScript с TypeScript. TypeScript представляет собой надмножество JavaScript, поэтому вся функциональность JS доступна в TS.
WebAssembly 1.0 aka MVP
Главный барьер для стремительного роста популярности Wasm — поэтапная разработка этой технологии. Из-за неё не все возможности WebAssembly можно широко применять. Версия 1.0, которую также назвали MVP, лучше всего подходит для языков типа C/C++ и Rust, но не всегда хорошо работает даже с ними.
Это правильное намеренное решение, так как стандарты языков и технологий постоянно совершенствуются. Разработчики получают обратную связь и принимают решения на её основе. Это позволяет избежать выпуска откровенно неудачных решений, которые потом практически невозможно изъять из обращения.
В будущем Wasm будет поддерживать высокоуровневые языки, например, Java и OCaml. Даже Dart, Elm и Reason когда-то будут компилироваться в WebAssembly. Одним из «отсутствующих кусочков» всё ещё является сборщик мусора (garbage collection, GC). GC работает в Wasm, но пока не очень эффективно.
Также проблемой остаётся прямой доступ к API DOM/HTML. Сейчас WebAssembly должен делать вызов с помощью JS, когда необходимо обратиться к WEB API. Wasm не может напрямую обрабатывать сгенерированные WEB API объекты. Поэтому инструментам вроде Emscripten и wasm-bindgen приходится делать дополнительную работу, чтобы скрыть этот факт от вас.
Как работать с WebAssembly
Здесь начинаются странности. Как вы помните, код компилируется в Wasm, вы не пишете его на WebAssembly вручную. Поэтому подходы к работе зависят от языка, на котором вы пишете и который собираетесь компилировать в Wasm.
Если вы пишете на C/C++, используйте Emscripten. Он оборачивает Clang/LLVM и выдаёт JavaScript-код, который может взаимодействовать с WEB API.
Если вы пишете на Rust, вам повезло. Разработчики ядра Rust активно работают над совместимостью с WebAssembly. Подробности можно узнать из книги Rust and WebAssembly .
Есть и другие языки, которые работают над поддержкой Wasm, например, Go.
Не Web, да и не ассемблер
В этой публикации речь идёт преимущественно об использовании WebAssembly в браузере. Стоит отметить, что название технологии вводит в заблуждение. Wasm — не ассемблер, это текстовое представление бинарного байт-кода.
Разработчики WebAssembly понимают, что само по себе сотрудничество нескольких технологических гигантов для выработки единого и свободного стандарта команд — беспрецедентное событие. И тем сильнее они заинтересованы в том, чтобы стандарт вообще не был жёстко к привязан к браузерам.
Что ещё важнее, WebAssembly не предназначен исключительно для веба. В настоящее время использование Wasm вне браузеров набирает обороты. Ниже несколько конкретных примеров.
- Nebulet . Микроядро операционной системы для запуска Wasm.
- wasmjit, виртуальная машина WebAssembly.
- Wasmer . Универсальная среда исполнения Wasm.
- Воркеры Cloudflare для запуска Wasm.
- Fastly Terrarium , среда для развёртывания Wasm.
- Ewasm . Виртуальная машина WebAssembly.
- Pariti wasmi , интерпретатор Wasm.
Заключение
WebAssembly можно использовать в современных браузерах. Это обеспечивает преимущества, когда крайне важна производительность. Однако сфера использования Wasm не ограничивается вебом. Это обещает интересное будущее для разработки в целом.
Адаптированный перевод публикации WebAssembly: Neither Web, Nor Assembly, but Revolutionary by Allen Conway. Мнение автора оригинальной публикации может не совпадать с мнением администрации «Хекслета».
Как мы при помощи WebAssembly в 20 раз веб-приложение ускорили
Если коротко, то это это бинарный формат инструкций для стековой виртуальной машины. Часто Wasm (сокращенное название) называют языком программирования, но это не так. Формат инструкций исполняется в браузере наряду с JavaScript.
Важно, что WebAssembly можно получить при компиляции исходников на таких языках, как C/C++, Rust, Go. Здесь применяется статистическая типизация и так называемая плоская модель памяти. Код, как сказано выше, хранится в компактном бинарном формате, благодаря чему выполняется почти так же быстро, как если бы приложение было запущено с помощью командной строки. Эти возможности и привели к росту популярности WebAssembly.
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».
Skillbox рекомендует: Практический курс «Мобильный разработчик PRO» .
На данный момент Wasm используется во многих приложениях, от игр вроде Doom 3 до портированных в веб приложений типа Autocad и Figma. Wasm применяется и в такой сфере, как serverless вычисления.
В этой статье приведен пример использования Wasm для ускорения аналитического веб-сервиса. Для наглядности мы взяли работающее приложение, написанное на С, которое скомпилируется в WebAssembly. Результат будет использован для замены малопроизводительных участков JS.
Трансформация приложения
В примере будет использоваться браузерный сервис fastq.bio, который предназначен для генетиков. Инструмент позволяет оценить качество секвенирования (расшифровки) ДНК.
Вот пример приложения в работе:
Подробности процесса не стоит приводить, поскольку они довольно сложны для неспециалистов, но если вкратце, то ученые по указанной выше инфографике могут понять, прошел ли процесс секвенирования ДНК гладко и какие возникли проблемы.
У этого сервиса есть альтернативы, десктопные программы. Но fastq.bio позволяет ускорить работу, визуализируя данные. В большинстве других случаев нужно уметь работать с командной строкой, но не у всех генетиков есть нужный опыт.
Работает все просто. На входе — данные, представляемые в виде текстового файла. Этот файл генерируется специализированными инструментами для секвенирования. В файле размещается список последовательностей ДНК и оценка качества для каждого нуклеотида. Формат файла .fastq, поэтому сервис и получил такое название.
Реализация на JavaScript
Первый шаг пользователя при работе с fastq.bio — выбор соответствующего файла. Используя объект File, приложение считывает случайную выборку данных из файла и обрабатывает этот пакет. Задача JavaScript здесь — выполнение несложных строковых операций и подсчет показателей. Один из них — количество нуклеотидов A, C, G и T на разных фрагментах ДНК.
После просчета нужных показателей они визуализируются при помощи Plotly.js, а сервис начинает работать с новой выборкой данных. Разделение на фрагменты сделано для повышения качества UX. Если работать со всеми данными сразу, процесс зависнет на какое-то время, поскольку файлы с результатами секвенирования занимают сотни гигабайтов файлового пространства. Сервис же берет участки данных размером от 0,5 до 1 Мб и работает с ними шаг за шагом, выстраивая графические данные.
Вот как это работает:
В красном прямоугольнике размещается алгоритм строковых преобразований для получения визуализации. Это наиболее нагруженная с точки зрения вычислений часть сервиса. Стоит попробовать заменить ее на Wasm.
Тестируем WebAssembly
Для оценки возможности использования Wasm команда проекта занялась поиском готовых решений для создания QC-метрики (QC — quality control) на основе файлов fastq. Поиск велся среди инструментов, написанных на С, С++ или Rust, чтобы была возможность портировать код на WebAssembly. Кроме того, инструмент не должен быть «сырым», требовался сервис, уже проверенный учеными.
В результате выбор был сделан в пользу seqtk . Приложение довольно популярно, оно open-source, исходный язык — С.
Перед преобразованием в Wasm стоит посмотреть принцип компиляции seqtk для десктопа. Согласно Makefile, вот то, что нужно:
# Compile to binary $ gcc seqtk.c -o seqtk -O2 -lm -lz
В принципе, скомпилировать seqtk можно при помощи Emscripten. Если его нет, обходимся образом Docker .
$ docker pull robertaboukhalil/emsdk:1.38.26 $ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26
При желании собрать его можно и самостоятельно , но на это нужно время.
Внутри контейнера без проблем можно взять emcc в качестве альтернативы gcc:
# Compile to WebAssembly $ emcc seqtk.c -o seqtk.js -O2 -lm -s USE_ZLIB=1 -s FORCE_FILESYSTEM=1
Вместо вывода в бинарный файл Emscripten для генерации файлов используется .wasm и .js, который применяется для запуска модуля WebAssemby.
Для поддержки библиотеки zlib используется флаг USE_ZLIB. Библиотека распространена и портирована на WebAssembly, а Emscripten включает ее в проект.
Активируется виртуальная файловая система Emscrippten. Это POSIX-подобная ФС , работающая в оперативной памяти внутри браузера. Когда страница обновляется, память очищается.
Чтобы понять, зачем нужна виртуальная файловая система, стоит сравнить способ запуска seqtk из командной строки со способом запуска скомпилированного модуля WebAssembly.
# On the command line $ ./seqtk fqchk data.fastq # In the browser console > Module.callMain(["fqchk", "data.fastq"])
Получение доступа к виртуальной файловой системе нужно, чтобы не переписывать seqtk под строковый, а не файловый ввод. В этом случае фрагмент данных отображается как файл data.fastq в виртуальной ФС с вызовом на нем main() seqtk.
Вот новая архитектура:
Рисунок демонстрирует, что вместо вычислений в основном потоке браузера используется WebWorkers . Этот способ дает возможность выполнять вычисления в фоновом потоке, не ухудшая отзывчивость браузера. Ну а контроллер WebWorker запускает Worker, управляя его взаимодействием с основным потоком.
Команда seqtk запускается при помощи Worker на примонтированном файле. После завершения выполнения Worker выдает результат в виде Promise. Когда сообщение получено главным потоком, результат используется для обновления графиков. И так в несколько итераций.
Что насчет производительности WebAssembly?
Для того, чтобы оценить изменение производительности, команда проекта воспользовалась параметром количества операций чтения в секунду. Время построения интерактивных графиков не учитывается, поскольку в обеих имплементациях используется JavaScript.
При использовании решения «из коробки» прирост производительности составил девять раз.
Это отличный результат, но, как оказалось, есть возможность оптимизировать и его. Дело в том, что большое количество результатов QC-анализа не используется seqtk, поэтому их можно удалить. Если это сделать, результат по сравнению с JS улучшается в 13 раз.
Достичь его удалось простым комментированием команд printf().
Но и это не все. Дело в том, что на этом этапе fastq.bio получает результаты анализа с вызовом разных функций С. Любая из них вычисляет свой набор характеристик, так что каждый фрагмент файла читался по два раза.
Для того, чтобы обойти это проблему, было решено совместить две функции в одну. В результате производительность увеличилась в 20 раз.
Стоит отметить, что такого выдающегося результата можно достичь далеко не всегда. В некоторых случаях производительность падает, так что стоит оценивать каждый конкретный случай.
В качестве вывода можно сказать, что Wasm действительно дает возможность улучшить производительность приложения, но использовать его нужно с умом.
- Двухлетний практический курс «Я — веб-разработчик PRO» .
- Онлайн-курс «С#-разработчик с 0» .
- Практический годовой курс «PHP-разработчик с 0 до PRO» .
Добавить комментарий Отменить ответ
Для отправки комментария вам необходимо авторизоваться.