Предыстория: начните с JavaScript
JavaScript превыше всего, будь то публичный или частный проект, любая организация, любая часть мира, JavaScript является номером один. - Годовой отчет GitHub за 2018 г.
С быстрым развитием JavaScript он стал одним из самых популярных языков программирования, что обусловлено развитием Интернета. Но поскольку JavaScript широко используется, он также обнажает множество проблем:
- Синтаксис слишком гибкий, что затрудняет разработку больших веб-проектов;
- Производительность не может удовлетворить потребности некоторых сценариев;
Эти две проблемы стали дамокловым мечом над головой JavaScript, ставя под угрозу более широкое применение JavaScript.
Брендан Эйх и представить себе не мог, что JavaScript, который он разработал в спешке за десять дней, сразу же после запуска получил широкое признание и стал использоваться большим количеством пользователей по всему миру. Предшественники выкопали яму, а вторые засыпали ее. Теперь, когда JavaScript стал стандартом де-факто для веб-программирования, необходимо решить эти две насущные проблемы.
Изучение MS, Google, Mozilla
МС: машинописный текст
Первую проблему решила Microsoft, известная компания-разработчик программного обеспечения с открытым исходным кодом.
Microsoft объединила главного архитектора C# и таких звезд, как Андерс Хейлсберг, основатель Delphi и Turbo Pascal, для создания TypeScript.
TypeScript является строгим надмножеством JavaScript и добавляет необязательную статическую типизацию и манипулирование Prototype с использованием того, что выглядит как синтаксис объектно-ориентированного программирования на основе классов. Итак, TypeScript может понимать это так:
Microsoft использовала острое оружие TypeScript для создания таких эпических проектов, как VSCode, то есть первый дамоклов меч.Синтаксис слишком гибкий, что затрудняет разработку крупных веб-проектов."Вроде бы решилось.
Однако, поскольку TypeScript по-прежнему компилируется в JavaScript и выполняется в браузере, проблемы с производительностью, которые досаждают разработчикам JavaScript, до сих пор не решены.
Гугл: V8
Еще в 2008 году Google запустил собственный движок JavaScript V8, пытаясь использовать технологию JIT для повышения скорости выполнения JavaScript, и это действительно удалось.
Благодаря внедрению технологии JIT, V8 позволил увеличить производительность Web в десятки раз!
На рисунке выше показаны результаты теста Chakra для Chrome v8 и IE. конкретный адреснажми на меня
Теперь, когда производительность значительно улучшилась, была ли решена проблема производительности JavaScript, о которой так много отзывались? Почему веб-производительность все еще находится под вопросом?
один поток -> блокировка
В веб-приложениях большинство узких мест производительности связаны не с JavaScript, а с DOM. Браузеры обычно реализуют DOM и JavaScript независимо друг от друга. На следующей диаграмме показана реализация DOM и JavaScript в разных браузерах:
Поскольку рендеринг Dom и движок JavaScript относительно независимы, когда эти два модуля обращаются друг к другу, доступ к ним осуществляется через интерфейсы. Из-за однопоточной природы JavaScript этот доступ может быть только симплексным.
DOM и JavaScript можно представить как острова, и они соединены мостами. Каждый раз, когда JavaScript посещает DOM, он должен пройти по мосту и оплатить сбор за переход. Чем больше посещений, тем выше стоимость. Поэтому рекомендуемая практика состоит в том, чтобы свести к минимуму пересечения мостов и остаться на острове JavaScript. Для этого можно использовать Virtual Dom, Web Worker. Я не буду здесь вдаваться в подробности.
JIT VS AOT, все еще бессильный перед лицом тяжелых вычислений
Как только что упоминалось, движок V8 впервые представил JIT-технологию в JavaScript, что значительно повысило скорость выполнения. Итак, сначала нам нужно понять, что такое JIT и AOT.
AOT: Ahead-of-Time compilation
Это должен быть строго типизированный язык.Перед компиляцией компиляция напрямую генерирует двоичный файл, который может быть выполнен ЦП.Во время выполнения ЦП не нужно выполнять какие-либо операции компиляции, и он выполняется напрямую с максимальной производительностью.
JIT: Just-in-Time compilation
Ссылки на компиляцию нет. Во время выполнения двоичный ассемблерный код генерируется в соответствии с контекстом и вводится в ЦП для выполнения. Когда выполняется JIT, его можно оптимизировать в соответствии с компиляцией кода. Когда код выполняется, его не нужно каждый раз переводить в двоичный ассемблерный код. Так V8 оптимизирует производительность JavaScript.
Поскольку тип динамического языка JavaScript нельзя изменить, производительность можно оптимизировать только в форме JIT.
Чтобы еще больше оптимизировать эффективность JIT, а затем повысить производительность JavaScript, Mozilla, создатель браузера, запустил asm.js.
Подобно TypeScript, asm.js также является строго типизированным JavaScript, но его синтаксис представляет собой подмножество JavaScript, специально созданное для оптимизации производительности JIT.
Типичный код asm.js выглядит следующим образом:
Как видите, asm.js использует побитовую операцию или операцию 0 для объявления x целым числом. Это гарантирует, что JIT сгенерирует соответствующий двоичный код как можно скорее в процессе выполнения, не оценивая тип переменной в соответствии с контекстом.
Mozilla дает бенчмарк для asm.js:
asm.js To WebAssembly
Поскольку Mozilla предложила asm.js, Google, Microsoft и Apple сочли asm.js хорошей идеей, поэтому они объединили усилия для создания экосистемы WebAssembly.
В отличие от asm.js, WebAssembly — это стандарт байт-кода, который использует виртуальную машину для запуска в браузере в виде байт-кода.
Вы можете положиться на такие компиляторы, как Emscripten, для компиляции строго типизированных языков, таких как C++/Golang/Rust/Kotlin, в байт-код WebAssembly (файл .wasm). Итак, WebAssembly — это не сборка, это просто похоже на сборку. Типичный файл .wasm выглядит так:
00000000: 0061 736d 0100 0000 0108 0260 017f 0060 .asm.......`...`
00000010: 0000 0215 0203 656e 7603 6d65 6d02 0001 ......env.mem...
00000020: 026a 7303 6c6f 6700 0003 0201 0107 0b01 .js.log.........
00000030: 0765 7861 6d70 6c65 0001 0a23 0121 0041 .example...#.!.A
00000040: 0042 c8ca b1e3 f68d c8ab ef00 3703 0041 .B..........7..A
00000050: 0841 f2d8 918b 0236 0200 4100 1000 0b .A.....6..A....
настоящий бой
Настройка среды: скомпилируйте Emscripten
На этот раз для компиляции файла WebAssembly и его выполнения в браузере используется официальный рекомендуемый язык CPP. Во-первых, вам нужно настроить среду Emscripten. Emscripten используется для преобразования файлов CPP в файлы байт-кода WASM.
Традиционный процесс строительства очень громоздкий:
1、确保安装CMake、Xcode、Python 2.7.x
2、git clone https://github.com/juj/emsdk.git
3、./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
等待约1个小时……,切换版本需要重新编译。
Однако люди из лучших побуждений приготовили для нас обходной путь:Использование образов Docker, быстро начните свой путь WebAssembly. Просто нужно выполнить следующие шаги:
1、安装Docker
2、docker pull trzeci/emscripten:latest
3、alias emcc='docker run –rm -v $(pwd):/src -u emscripten trzeci/emscripten emcc’
切换版本只需要pull相应的tag
Скомпилируйте функцию MD5 CPP в WASM
Во-первых, вам нужно найти код CPP для расчета MD5:
git@github.com:codenoid/md5-cpp.git
Используйте макрос EMSCRIPTEN_KEEPALIVE в emscripten.h, чтобы гарантировать, что компилятор emcc не оптимизирует эту функцию, поскольку она не вызывается при компиляции.
Здесь uint8_t* неявно преобразуется в тип char*
Используйте emcc для компиляции файла CPP в файл WASM:
emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]’ md5.c
-
-O3: уровень оптимизации, O3 — самый высокий уровень оптимизации
-
-s WASM=1: генерировать код wasm вместо кода asm.js.
-
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' : использовать функцию экспорта ссылки на функцию cwrap в JavaScript
Наконец, будут сгенерированы два файла a.out.js и a.out.wasm. Это связующий файл для взаимодействия WASM и JavaScript и файл байт-кода WebAssembly.
Вычислите md5 и выведите результат:
Здесь следует отметить две вещи:
- a.out.js автоматически получит файл wasm.Поскольку файл wasm также является междоменным, вы можете использовать http-сервер для локального запуска сервера.
- CPP и тип переменного типа переменного типа JavaScript должны быть преобразованы, преобразование автоматически выполняется кодом клея, конкретное правило преобразования выглядит следующим образом:
benchmark
Поскольку WebAssembly фокусируется на повышении производительности, необходимы тесты.Для коротких символов "ivweb", зашифрованных 100 000 раз, результаты тестов следующие:
Видно, что по сравнению с чистым JavaScript вычислительная производительность WebAssembly повышается примерно на 39%, что далеко от общего повышения производительности на 100%+. Почему это?
Я снова проверил 2-мегабайтный длинный текст, и результаты следующие:
На этот раз улучшения больше. Чем вызван такой большой разрыв? Я предполагаю, что есть две причины:
- Когда короткий символ «ivweb» шифруется 100 000 раз, после JIT-оптимизации нет необходимости каждый раз компилировать, и производительность JavasScript значительно улучшилась.
- Когда короткий символ «IVWeb» зашифрован 100 000 раз, код клея выполняется много раз, что замедляет производительность.
В ответ на два вышеупомянутых предположения был сделан еще один набор тестов для шифрования «ivweb» 5 000 000 раз.
Видно, что разрыв в производительности между WebAssembly и чистым JavaScript невелик, что подтверждает мою догадку.
Этот тестовый код я загрузил в репозиторий GitHub:
git@github.com:PeacefulLion/wasm-benchmark.git
открытие
Учитывая высокую производительность V8, вам не нужна WebAssembly в 90% сценариев приложений.
Просветление: как улучшить производительность кода JS?
- Предоставляйте типы по умолчанию при объявлении переменных, ускоряя вмешательство JIT
- Не меняйте легкомысленно тип переменной
- Node.js также имеет JIT-разминку, как JAVA?
Резюме и перспективы
WebAssembly еще не идеален. Но поддержка потоков, обработка исключений, сборка мусора, оптимизация хвостовых вызовов и т. д. были добавлены в список планов WebAssembly.
В будущем WebAssembly можно будет использовать для:
- Расширенные возможности обработки видео и аудио на стороне браузера (H.265)
- Высокопроизводительные веб-приложения на основе WebAssembly (шифрование, игры, майнинг?)
В настоящее время Webpack4 уже поддерживает вызов файлов wasm в виде файлов импорта wasm.
В будущем на WebAssembly, скорее всего, будут ссылаться напрямую через теги HTML, например:
<script src="./wa.wasm"></script>;
Или на него можно ссылаться как на модуль JavaScript ES6, например:
import xxx from './wa.wasm';;
Обмен ресурсами
Менеджер пакетов WebAssembly
Онлайн CPP в WASM
Справочная статья
Статус-кво WebAssembly и реальный бой
Разработка и расшифровка веб-плеера H.265
Потихоньку поднимаем тайну WebAssembly
Подпишитесь на официальный аккаунт [IVWEB Community], чтобы получать свежие статьи каждую неделю, ведущие к вершине жизни!