Источник изображения:rustwasm.github.io/
Автор этой статьи:Лю Цзялун
написать впереди
Эта статья надеется постучать в дверь WebAssembly через Rust. В качестве вводной статьи я надеюсь помочь вам понять WebAssembly и создать простое приложение WebAssembly. Независимо от ситуации с IE, большинство основных браузеров уже поддерживают WebAssembly, особенно на мобильной стороне, поддерживаются основные UC, ядро X5, Safari и т. д. Я надеюсь, что прочитав эту статью, она поможет вам применить WebAssembly в производственной среде.
Введение в WebAssembly (wasm)
Если вы действительно понимаете WebAssembly, вы можете пропустить этот раздел.
Сначала вы можете посмотреть еще две классические демонстрации wasm:
Краткий обзор: WebAssembly (WASM) — это новый переносимый, компактный, быстрый и совместимый с Интернетом формат, а также новые спецификации, разработанные W3C. Цель состоит в том, чтобы заменить JS в некоторых сценариях, таких как игры, редактирование изображений/видео, ar/vr. Говоря о людях, он меньше по размеру и бегает быстрее.
wasm имеет два формата представления: текстовый и двоичный. Двоичный формат может быть помещен в песочницу на виртуальной машине браузера js или в других небраузерных средах, таких как среда общего узла; запуск в Интернете является исходным намерением оригинального дизайна wasm, поэтому его можно реализовать при просмотре. работы на устройстве очень просто.
Простой пример быстрой компиляции текста wasm и запуска бинарного файла wasm:
код формата текста wasm:
(module
(import "js" "import1" (func $i1)) // 从 js 环境中导入方法1
(import "js" "import2" (func $i2)) // 从 js 环境中导入方法2
(func $main (call $i1)) // 调用方法1
(start $main)
(func (export "f") (call $i2)) // 将自己内部的方法 f 导出,提供给 js,当 js 调用,则会执行方法2
)
Приведенное выше содержимое можно увидеть примерно, и вы можете обратиться к комментариям в коде, чтобы получить общее представление о синтаксисе основной функции. Основная функция — импортировать два метода из среды jsimport1
а такжеimport2
; при определении метода сам по себеf
И экспорт предоставляется во внешние вызовы, и выполняется тело методаimport2
.
Сам текстовый формат не может быть выполнен в браузере и должен быть скомпилирован в двоичный формат. в состоянии пройтиwabtСкомпилируйте текстовый формат в бинарный.Обратите внимание, что сам текстовый формат не поддерживает написание комментариев, и его нужно удалить при компиляции. использовать здесьонлайн-инструмент wat2wasmБыстрая компиляция, загрузка результата компиляции — бинарный файл wasm, необходимый для запуска.
С двоичным файлом все, что осталось, — это выполнить вызов в браузере.
// 定义 importObj 对象赋给 wasm 调用
var importObj = {js: {
import1: () => console.log("hello,"), // 对应 wasm 的方法1
import2: () => console.log("world!") // 对应 wams 的方法2
}};
// demo.wasm 文件就是刚刚下载的二进制文件
fetch('demo.wasm').then(response =>
response.arrayBuffer() // wasm 的内存 buffer
).then(buffer =>
/**
* 实例化,返回一个实例 WASM.module 和一个 WASM.instance,
* module 是一个无状态的 带有 Ast.module 占位的对象;
* 其中instance就是将 module 和 ES 相关标准融合,可以最终在 JS 环境中调用导出的方法
*/
WebAssembly.instantiate(buffer, importObj)
).then(({module, instance}) =>
instance.exports.f() // 执行 wasm 中的方法 f
);
Кратко опишите процесс выполнения функции:
- определить один в js
importObj
объект, переданный в среду wasm, предоставляющий методыimport1
import2
упоминается wasm; - Получить поток бинарных файлов через выборку и получить буфер памяти;
- Создание экземпляра из буфера памяти через глобальный объект браузера WebAssembly, т.е.
WebAssembly.instantiate(buffer, importObj)
, который выполнит wasmmain
метод, который вызоветimport1
, консоль выводит привет; - После создания экземпляра wasm возвращается, и метод в wasm может быть вызван через этот экземпляр, таким образом реализуя двустороннее соединение и выполняя
instance.exports.f()
вызовет метод в wasmf
,f
снова вызовет в среде jsimport2
, консоль выводит world.
Глядя на эту реализацию, можно ли вызвать js в wasm, чтобы косвенно реализовать операции, связанные с браузером, в среде wasm? Разверните это ниже.
Очевидно, это не то, что мы хотим реализовать wasm, напрямую написав текстовый формат, так есть ли способ «говорить с людьми»? В настоящее время лучше поддерживаются в основном C, C++, Rust, Lua и т. д.
Характерная ржавчина
Если вы знаете Rust, этот раздел также можно пропустить.
Язык, позволяющий каждому создавать надежное и эффективное программное обеспечение.rust-lang
Rust был назван самым популярным языком 2019 года.
Скриншот изинсайты.stackoverflow.com/survey/2019…
Rust официально родился в 15 лет, всего менее пяти лет назад, но он охватил крупные компании, такие как Amazon, Google, Facebook, Dropbox и другие гиганты за рубежом, а также отечественные компании Alibaba, Toutiao, Zhihu, Bilibili и т.д. Так что же заставляет такой молодой язык расти так быстро?
- Rust фокусируется на безопасности, параллелизме и производительности.Для достижения этой цели язык Rust следует трем философиям проектирования: безопасность памяти, абстракция с нулевой стоимостью и практичность.
- Работает кроссплатформенно с LLVM.
- В Rust нет сборщика мусора во время выполнения, и в большинстве случаев вам не нужно беспокоиться об утечках памяти.
- ...
Вы не можете выучить ОС в своем сердце? Не волнуйтесь, сначала кратко оцените прелесть Rust, может быть, вы будете им очарованы.
Следующий, казалось бы, простой вопрос, сможете ли вы правильно на него ответить? Всего три строчки кода.С самим синтаксисом проблем нет.Угадайте,что получится в результате печати?
fn main() {
let s1 = String::from("hello word"); // 定义一个字符串对象
let s2 = s1; // 赋值
println!("{}", s1); // log输出
}
Подумай немного Нажмите, чтобы увидеть ответ
Ошибка! Переменная s1 больше не существует.На самом деле это одна из наиболее важных особенностей Rust — владение. когда будетs1
назначить наs2
Позже,s1
Право собственности наs1
был уничтожен. Благодаря этой функции управление памятью предварительно позиционируется, и память контролируется в процессе написания кода.В то же время с помощью статической проверки можно гарантировать нормальную работу большинства правильно скомпилированных программ, что не только улучшает безопасность памяти, но также повышает производительность программы, надежность и улучшает контроль разработчика.
Владение — это лишь одна из многих особенностей Rust.В нем много отличных идей, связанных с тремя его философиями (безопасность, параллелизм и производительность), что также указывает на то, что стоимость начала работы по-прежнему относительно высока.Если вам интересно, вы можете узнать больше об этом. Ранее в Rust были созданы четыре рабочие группы CLI, сети, WASM и встраиваемых систем, что указывает на четыре направления, в которых Rust надеется развиваться. До сих пор были относительно полные реализации во многих областях, таких как actix-web в направлении серверной части, yew в направлении веб-интерфейса и wasm-pack в направлении wasm. Одним словом, Rust — очень интересный язык, способный расширить границы возможностей.Хотя вход и крутой, но изучить его рекомендуется, может быть, вы влюбитесь в него по уши.
Помимо wasm в других направлениях (cli, server и т.д.), мне еще нравится go, потому что оно простое, ^_^ escape...
Ладно, после стольких разговоров, почему Rust подходит для wasm:
- Сборщик мусора во время выполнения не требуется, JIT не требуется, производительность гарантирована
- Отсутствует код сборки мусора, а размер wasm может быть гарантированно уменьшен за счет оптимизации кода.
- Высокая поддержка (официальное вмешательство), в настоящее время по сравнению с другими языками экология более полная, что обеспечивает низкую стоимость разработки
Rust -> wasm
Цель компиляции Rust
rustc сам по себе является кросс-платформенным компилятором, и существует множество целей компиляции, которые можно указать с помощьюrustup target list
View, есть три основных, связанных с компиляцией wasm:
- wasm32-wasi: в основном используется для достижения кросс-платформенного, кросс-платформенного модуля, общего для среды выполнения wasm, без специальных веб-атрибутов.
- wasm32-unknown-emscripten: сначала нужно знатьemscripten, который легко поддерживает компиляцию rust с помощью LLVM. Целевой продукт обеспечивает поддержку стандартной библиотеки через emscripten, чтобы гарантировать, что целевой продукт может работать полностью, тем самым реализуя независимое кросс-платформенное приложение.
- wasm32-unknown-unknown: главный герой выходит на сцену, чтобы добиться чистой компиляции из rust в wasm, без необходимости в огромной библиотеке C, поэтому размер продукта меньше. Выделение кучи достигается с помощью распределителя памяти (wee_alloc), поэтому мы можем использовать столько структур данных, сколько захотим, таких как Map, List и т. д. Используйте wasm-bindgen, web-sys/js-sys для взаимодействия с js, ECMAScript и веб-API. Целевая цепочка также в настоящее время находится на официальном обслуживании.
Некоторым может показаться немного странным название wasm32-unknown-unknown. Вот общее объяснение: wasm32 представляет собой адрес шириной 32 бита, и в будущем может быть wasm64. Первое неизвестное означает, что его можно скомпилировать. с любой платформы, а второе неизвестное означает, что его можно адаптировать под любую платформу.
wasm-pack
Приведенные выше наборы инструментов выглядят сложными и поддерживаются официальной разработкой.wasm-packИнструмент может скрыть все эти детали.На основе цепочки инструментов wasm32-unknown-unknown можно быстро реализовать компиляцию и упаковку пакетов Rust -> wasm -> npm, чтобы реализовать быстрый вызов в Интернете и отслеживание в Интернете. "слон" пакета wasm-npm. Достаточно выполнить следующие шаги:
- использоватьrustupустановить ржавчину
- Установить wasm-pack
- wasm-pack new hello-wasm.
- cd hello-wasm
- Запустите сборку wasm-pack.
- Продукт в каталоге pkg — это node_module, который можно вызывать обычным образом.
Реальный пример, чтобы увидеть преимущества работы wasm
Дорога проложена, можно идти! Далее, вы можете с удовольствием использовать ржавчину для написания wasm, это чешется?Давайте сравним скорость работы wasm и js, реализуя метод шифрования MD5.
Сначала измените Cargo.toml и добавьте пакеты зависимостей.
[dependencies]
wasm-bindgen = "0.2"
md5 = "0.7.0"
CargoЭто менеджер пакетов для Rust, который используется для публикации, скачивания, компиляции пакетов Rust и т. д. Вы можете запросить нужные вам пакеты по запросу. Среди них md5 — пакет алгоритмов, который через какое-то время будет зашифрован с помощью md5, и wasm-bindgen — набор инструментов, который помогает взаимодействовать wasm и js, сглаживая детали реализации и облегчая связь между двумя пространствами памяти.
Напишите реализацию (src/lib.rs)
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn digest(str: &str) -> String {
let digest = md5::compute(str);
let res = format!("{:x}", digest);
return res;
}
С помощью wasm_bindgen методы можно быстро экспортировать в js для вызова, так что вам не нужно заботиться о деталях связи с памятью. Наконец, пакет (в каталоге pkg) создается с помощью сборки wasm-pack, на которую можно напрямую ссылаться в Интернете.Продукт в основном включает следующие части.
├── package.json
├── README.md
├── *.ts
├── index_bg.wasm:生成 wasm 文件,被index.js进行调用
├── index.js:这个就是最终被 ECMAScript 项目引用的模块文件,里边包含我们定义的方法以及一些自动生成的胶水函数,利用 TextEncoder 实现内存之间的数据通信。
вызов js
import * as wasm from "./pkg";
wasm.digest('xxx');
Собранный пакет wasm pkg вводится в веб-проект, упаковывается и компилируется с помощью webpack@4, и для его поддержки даже не нужны никакие другие плагины.
сравнение скорости
Грубое сравнение скорости для шифрования md5 строки длиной около 220 000 символов:
Время шифрования (мс) | Время для 100-кратного шифрования (мс) | Пакет зависимостей алгоритма | |
---|---|---|---|
js версия md5 | ~57 | ~1300 | www.npmjs.com/package/md5 |
васм версия md5 | ~5 | ~150 | crates.io/crates/md5 |
На уровне данных преимущества wasm в производительности очевидны. Но в то же время также обнаружено, что во время 100 раз, хотя разница в данных о производительности увеличивается, соотношение меньше, чем у одного шифрования. Причина в том, что доля затрат на связь между js и wasm постепенно увеличивается при многократном шифровании, в результате чего время шифрования не увеличивается пропорционально, что также показывает, что фактическое время работы шифрования wasm меньше, чем результат. Это фактически показывает сценарий применения wasm в Интернете: тяжелые вычисления, легкое взаимодействие, такое как обработка аудио/видео/изображений, игры, шифрование. Но в будущем это также будет улучшено соответственно, с помощьюinterface-typeМожет быть достигнута более эффективная передача стоимости, и будущая интерфейсная структура может действительно открыть революцию.
Реализация полного веб-приложения с wasm
с помощьюwasm-bindgen
,js-sys
а такжеweb-sys
ящики, мы можем даже минимально полагаться на js для завершения полного веб-приложения. Ниже приведено приложение web-wasm, которое преобразует исходные цветные изображения PNG в черно-белые изображения.
Изображение эффекта:
онлайн опыт:нажми на меня
Общая функция заключается в чтении файлов через js, использовании wasm для обработки черно-белых изображений и непосредственном создании dom и рендеринге изображений через wasm.
1. Используйте js для реализации простого чтения файлов:
// html
<div>
<input type="file" id="files" style="display: none" onchange="fileImport();">
<input type="button" id="fileImport" value="选择一张彩色的png图片">
</div>
// js
$("#fileImport").click(function () {
$("#files").click();
})
window.fileImport = function() {
//获取读取我文件的 File 对象
var selectedFile = document.getElementById('files').files[0];
var reader = new FileReader(); // 这是核心, 读取操作就是由它完成.
reader.readAsArrayBuffer(selectedFile); // 读取文件的内容,也可以读取文件的URL
reader.onload = function () {
var uint8Array = new Uint8Array(this.result);
wasm.grayscale(uint8Array);
}
}
Полученный здесь файл является js-объектом, и окончательно полученную информацию о файле необходимо передать в wasm через память, а файловый объект нельзя напрямую передать в пространство wasm. Мы можем передать данные, преобразовав файл изображения в 8-битный беззнаковый массив через FileReader. На этом миссия в js-пространстве завершена, и наконец вам нужно только позвонитьwasm.grayscale
передайте данные в wasm.
2. wasm извлекает данные и реорганизует
fn load_image_from_array(_array: &[u8]) -> DynamicImage {
let img = match image::load_from_memory_with_format(_array, ImageFormat::Png) {
Ok(img) => img,
Err(error) => {
panic!("{:?}", error)
}
};
return img;
}
#[wasm_bindgen]
pub fn grayscale(_array: &[u8]) -> Result<(), JsValue> {
let mut img = load_image_from_array(_array);
img = img.grayscale();
let base64_str = get_image_as_base64(img);
return append_img(base64_str);
}
Пространство wasm получает переданный массив, и его необходимо реорганизовать в объект файла изображения.Используя готовый крейт изображения колеса, можно быстро преобразовать из беззнакового массива в объект изображения (load_image_from_array
), и черно-белая обработка изображения (img.grayscale()
). Обработанный объект нужно окончательно вернуть в браузер<img />
Информация о содержимом, идентифицируемая тегом, предоставляется интерфейсу для предварительного просмотра.Здесь выбрана строка base64.
3. Создайте формат изображения base64 в wasm
fn get_image_as_base64(_img: DynamicImage) -> String {
// 创建一个内存空间
let mut c = Cursor::new(Vec::new());
match _img.write_to(&mut c, ImageFormat::Png) {
Ok(c) => c,
Err(error) => {
panic!(
"There was a problem writing the resulting buffer: {:?}",
error
)
}
};
c.seek(SeekFrom::Start(0)).unwrap();
let mut out = Vec::new();
// 从内存读取数据
c.read_to_end(&mut out).unwrap();
// 解码
let stt = encode(&mut out);
let together = format!("{}{}", "data:image/png;base64,", stt);
return together;
}
Преобразуйте объект DynamicImage в базовое значение в пространстве wasm, чтобы снова реализовать передачу значения; с помощью Rust Cursor читайте и записывайте информацию объекта DynamicImage.Rust Cursor немного похож на внешний интерфейс Устройство чтения/записи, которое осуществляет чтение и запись информации через буферную область. Чтобы получить информацию о хранении изображения в пространстве памяти, полученная информация может получить информацию об исходной строке после декодирования base64 и информацию о формате сращивания полученной строки.data:image/png;base64
После формирования полного создания персонажа ресурса изображения его можно напрямую вернуть во внешний интерфейс для предварительного рендеринга.
Вышеупомянутое завершило весь процесс обработки изображения, и полученный base64 можно напрямую вернуть в js для создания предварительного просмотра dom. но! Могу ли я сделать это без использования js и сделать это прямо в wasm?
4. Создаем dom и рендерим изображения в wasm
Сам Wasm не может напрямую управлять DOM, он должен пройти через js, чтобы завершить операцию DOM. Однако по-прежнему можно загрузить модуль js в wasm для косвенного управления dom.web_sysЭтот шаг реализован, и все реализации интерфейса в основном завершены.С помощью web_sys можно легко реализовать чистый интерфейсный фреймворк wasm, такой как yew.
Изображение взято из:hacks.Mozilla.org/2017/02/me и…
pub fn append_img(image_src: String) -> Result<(), JsValue> {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let body = document.body().expect("document should have a body");
let val = document.create_element("img")?;
val.set_attribute("src", &image_src)?;
val.set_attribute("style", "height: 200px")?;
body.append_child(&val)?;
Ok(())
}
Процесс работы в основном такой же, как и при непосредственном использовании js для работы с dom, фактически он также косвенно вызывает метод стороны js. В практических приложениях по-прежнему необходимо стараться избегать дополнительных потерь производительности, вызванных многочисленными коммуникациями.
Простое приложение для обработки черно-белых изображений завершено, полный код:нажми на меня. Аналогичным образом можно расширить и другие функции, такие как сжатие, кадрирование и т. д.
напиши в конце
В этой статье кратко описывается процесс перехода от Rust к wasm, а затем к wasm, основанному на сети. Я надеюсь, что после прочтения этой статьи я смогу помочь вам разработать идеи для решения проблем в реальном развитии бизнеса и исследовать все больше и больше практических сценариев. В связи с ограниченным уровнем автора критика и исправления приветствуются.
Ссылка на данные
business.life/docs/v/this_from…
hacks.Mozilla.org/2017/02/me и…
Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, может быть свободно воспроизведено, пожалуйста, указывайте перепечатку в заголовке и сохраняйте источник на видном месте. Мы всегда нанимаем, если вы готовы сменить работу и вам нравится облачная музыка, тоПрисоединяйтесь к нам!