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

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

Как работают потоки WebAssembly


В WebAssembly они представляют не отдельную возможность, а комбинацию нескольких компонентов, позволяющих приложениям wasm (сокращенно от WebAssembly) использовать в веб традиционные многопоточные парадигмы.

▍Веб-воркеры


Первым компонентом выступают стандартные воркеры, которых мы все знаем и ценим еще по JavaScript. Потоки wasm используют конструктор new Worker для создания новых внутренних потоков. Каждый поток загружает связующий JS-код, после чего основной поток через метод Worker#postMessage предоставляет другим потокам общий доступ к скомпилированному WebAssembly.Module, а также общему WebAssembly.Memory (см. ниже). Таким образом устанавливается связь и все потоки могут выполнять один код wasm в общей области памяти, не проходя повторно через JS.

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

▍SharedArrayBuffer


Память wasm представлена в JavaScript API объектом WebAssembly.Memory. По умолчанию WebAssembly.Memory является оберткой вокруг ArrayBuffer – буфера необработанных байтов, к которым может обращаться только один поток.

> new WebAssembly.Memory({ initial:1, maximum:10 }).buffer
ArrayBuffer { … }

С целью поддержки многопоточности для WebAssembly.Memory также появилась совместно используемая версия. При создании с флагом shared через JavaScript API или самим бинарником WebAssembly он становится оберткой вокруг SharedArrayBuffer. Это вариация ArrayBuffer, которую могут совместно использовать и другие потоки, и которая позволяет одновременное считывание и изменение с любой стороны.

> new WebAssembly.Memory({ initial:1, maximum:10, shared:true }).buffer
SharedArrayBuffer { … }

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

История SharedArrayBuffer достаточно сложна. Изначально его поддержка появилась в ряде браузеров в середине 2017 года, но в связи с обнаружением уязвимостей Spectre ее пришлось прекратить. Причиной, в частности, стало то, что извлечение данных через Spectre опирается на атаку по времени – измерение времени выполнения конкретного фрагмента кода. Чтобы усложнить реализацию подобных атак, в браузерах снизили точность стандартных API тайминга, таких как Date.now и performance.now. Однако общая память, совмещенная с простым циклом счетчика, выполняющимся в отдельном потоке, также является очень надежным способом получения высокоточного тайминга. Причем данную проблему гораздо сложнее устранить без существенного влияния на скорость выполнения.

Вместо этого в Chrome 68 (середина 2018) снова активировали SharedArrayBuffer, задействовав изоляцию сайтов – возможность, которая помещает разные сайты в разные процессы и намного усложняет использование одноканальных атак вроде Spectre.

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

Теперь перенесемся в 2020 год. Chrome и Firefox уже внедрили изоляцию сайтов, предоставив им стандартный способ подключения к этой возможности через заголовки COOP (Cross-Origin Opener Policy) и COEP (Cross-Origin-Embedder-Policy). Механизм подключения позволяет использовать ее даже на маломощных устройствах, где применение изоляции для всех сайтов оказалось бы слишком дорогостоящим. Для подключения нужно добавить следующие заголовки в основной файл конфигурации сервера:

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

После подключения вы получите доступ к SharedArrayBuffer (включая WebAssembly.Memory с поддержкой SharedArrayBuffer), точным таймерам, измерению памяти и другим API, из соображений безопасности требующим изолированности источника. Более подробно об этом можете узнать из статьи Making your website «cross-origin isolated» using COOP and COEP.

▍Атомарные операции WebAssembly


При том, что SharedArrayBuffer позволяет каждому потоку производить чтение/запись одной области памяти, для корректного взаимодействия нужно исключить возможность одновременного выполнения ими конфликтующих операций. К примеру, один поток может начать чтение данных из общего адреса, в то время как другой поток туда записывает, что приведет к получению первым поврежденного результата. Эта категория багов описывается как состояние гонки. Для того, чтобы его избежать, нужно подобные обращения потоков синхронизировать. Здесь и пригождаются атомарные операции.

Эти операции расширяют набор инструкций wasm, позволяя считывать и записывать небольшие участки памяти данных (обычно 32- и 64-битные целые числа) атомарно. Это в некотором смысле гарантирует, что два потока не будут считывать/записывать одну и ту же ячейку памяти одновременно, предотвращая возникновение подобных конфликтов на низком уровне. Кроме того, атомарные операции содержат еще два вида инструкций – wait и notify – которые позволяют одному потоку находиться в ожидании (wait) заданного адреса памяти, пока другой поток его не уведомит (notify) о том, что доступ свободен.

Все высокоуровневые примитивы синхронизации, включая каналы, мьютексы и блокировки чтения-записи, строятся на основе этих инструкций.

Как использовать потоки WebAssembly



▍Обнаружение возможностей


Атомарные операции и SharedArrayBuffer являются относительно новыми возможностями и пока еще доступны не во всех браузерах с поддержкой WebAssembly. Уточнить, в каких именно браузерах доступно их использование, можно в плане развития на сайте webassembly.org.

Для обеспечения возможности скачивания вашего приложения всеми пользователями нужно будет реализовать прогрессивное улучшение, создав две версии wasm – одну с поддержкой многопоточности и вторую без нее. Затем загружать поддерживаемую версию в зависимости от результатов обнаружения возможностей. Для определения при запуске наличия поддержки потоков используйте библиотеку wasm-feature-detect, и загружайте соответствующий модуль так:

import { threads } from 'wasm-feature-detect';

const hasThreads = await threads();

const module = await (
  hasThreads
    ? import('./module-with-threads.js')
    : import('./module-without-threads.js')
);

// …теперь можно использовать `module` как обычно

Далее рассмотрим процесс создания многопоточной версии модуля WebAssembly.

▍C


В Си, в частности в Unix-системах, обычно потоки используются через стандарт POSIX Threads, предлагаемый библиотекой pthread. Emscripten предоставляет API-совместимую реализацию pthread, созданную на базе веб-воркеров, совместно используемой памяти и атомарных операций, в результате чего один и тот же код может работать в веб без изменений.

Взглянем на пример:

example.c:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void *thread_callback(void *arg)
{
    sleep(1);
    printf("Inside the thread: %d\n", *(int *)arg);
    return NULL;
}

int main()
{
    puts("Before the thread");

    pthread_t thread_id;
    int arg = 42;
    pthread_create(&thread_id, NULL, thread_callback, &arg);

    pthread_join(thread_id, NULL);

    puts("After the thread");

    return 0;
}

Здесь заголовки для библиотеки pthread добавлены через pthread.h. Также мы видим пару важных функций для работы с потоками.

pthread_create() создает фоновый поток. Она получает путь для хранения обработчика потока, атрибуты для создания потока (здесь они отсутствуют, поэтому значение NULL), обратный вызов для выполнения в новом потоке (здесь thread_callback) и дополнительный аргумент-указатель для передачи в этот обратный вызов на случай, если вам потребуется поделиться данными из основного потока – в текущем примере мы делимся указателем на переменную arg.

pthread_join() можно вызвать позже в любое время для ожидания завершения выполнения потоком задачи и получения результата, возвращенного его обратным вызовом. Она принимает ранее определенный обработчик потока, а также указатель для сохранения результата. В данном случае результатов нет, поэтому функция получает в качестве аргумента NULL. Чтобы скомпилировать код с помощью Emscripten, используя потоки, нужно вызвать emcc и передать ей параметр -pthread, как в случаях компиляции того же кода на других платформах с помощью Clang или GCC:

emcc -pthread example.c -o example.js

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

Before the thread
Tried to spawn a new thread, but the thread pool is exhausted.
This might result in a deadlock unless some threads eventually exit or the code
explicitly breaks out to the event loop.
If you want to increase the pool size, use setting `-s PTHREAD_POOL_SIZE=...`.
If you want to throw an explicit error instead of the risk of deadlocking in those
cases, use setting `-s PTHREAD_POOL_SIZE_STRICT=2`.
[…hangs here…]

Что случилось? Проблема в том, что большинство времязатратных API в веб являются асинхронными, и их выполнение опирается на цикл событий. Это ограничение представляет важное отличие от традиционных сред, где приложения обычно выполняют процессы ввода/вывода синхронно с блокированием. Если хотите узнать об этом больше, почитайте Using asynchronous web APIs from WebAssembly.

В этом же случае код синхронно вызывает pthread_create() для создания фонового потока, а затем выполняет также синхронный вызов pthread_join(), которая ожидает завершения выполнения задачи фоновым потоком.

Тем не менее веб-воркеры, используемые внутренне при компиляции кода Emscripten, работают асинхронно. Поэтому pthread_create() только планирует создание нового потока воркера при очередном выполнении цикла событий, но затем pthread_join() сразу же блокирует цикл событий в ожидании этого воркера, тем самым не позволяя его даже создать.

Это классический пример взаимной блокировки.

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

Именно такую возможность и дает Emscripten через опцию -s PTHREAD_POOL_SIZE=…. Она позволяет указывать количество потоков, используя либо фиксированное число, либо выражение JavaScript вроде navigator.hardwareConcurrency, позволяющее создать их согласно количеству ядер ЦП. Второй вариант пригождается в случаях, когда код может масштабироваться на любое количество потоков.

В примере выше создается всего один поток, поэтому вместо резервирования всех ядер достаточно использовать -s PTHREAD_POOL_SIZE=1:

emcc -pthread -s PTHREAD_POOL_SIZE=1 example.c -o example.js
На этот раз при выполнении все сработает как надо:
Before the thread
Inside the thread: 42
After the thread
Pthread 0x701510 exited.

Хотя есть здесь другая проблема: видите в примере кода команду sleep(1)? Она выполняется в обратном вызове потока, то есть вне основного потока, и вроде как сложностей быть не должно, верно? Вообще-то, нет.

При вызове pthread_join() должна ожидать окончания выполнения потока, то есть если созданный поток занят длительными задачами – в этом случае ожиданием в течение 1 секунды – основной поток будет вынужден также заблокироваться на то же количество времени, пока не вернется результат. При выполнении этого JS-кода в браузере он заблокирует поток UI на одну секунду, пока обратный вызов потока не вернет результат. В итоге страдает пользовательский опыт.

Для этого есть несколько решений:
  • pthread_detach
  • -s PROXY_TO_PTHREAD
  • Собственный воркер и Comlink

▍pthread_detach


Если вам нужно просто выполнять задачи вне основного потока без необходимости дожидаться результатов, то вместо pthread_detach() можно использовать pthread_join(). Это оставит обратный вызов потока выполняющимся в фоновом режиме. Если вы используете этот вариант, то можете отключить предупреждение, указав -s PTHREAD_POOL_SIZE_STRICT=0.

▍PROXY_TO_PTHREAD


Если вы компилируете приложение Си, а не библиотеку, то можете использовать опцию -s PROXY_TO_PTHREAD, которая выгрузит основной код приложения в отдельный поток дополнительно к любым вложенным потокам, созданным самим приложением. Таким образом, основной код сможет в любой момент блокироваться безопасно, не тормозя UI.

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

▍Comlink


Если вы работаете над библиотекой и при этом нуждаетесь в блокировке, то можете создать собственного воркера, импортировать сгенерированный Emscripten код и представить его основному потоку с помощью Comlink. Основной поток сможет вызывать любые экспортированные методы как асинхронные функции, избегая таким образом блокировки UI.

В простом приложении, наподобие приведенного в примере выше, наилучшим вариантом будет -s PROXY_TO_PTHREAD:

emcc -pthread -s PROXY_TO_PTHREAD example.c -o example.js

▍C++


Все описанное также применимо и к С++. Единственное, что вы получаете дополнительно – это доступ к высокоуровневым API, таким как std:thread и std:async, которые внутренне используют описанную ранее библиотеку pthread.

Поэтому пример выше можно более идиоматическим образом переписать на C++ так:

example.cpp:
#include <iostream>
#include <thread>
#include <chrono>

int main()
{
    puts("Before the thread");

    int arg = 42;
    std::thread thread([&]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::cout << "Inside the thread: " << arg << std::endl;
    });

    thread.join();

    std::cout << "After the thread" << std::endl;

    return 0;
}

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

emcc -std=c++11 -pthread -s PROXY_TO_PTHREAD example.cpp -o example.js
Вывод:
Before the thread
Inside the thread: 42
Pthread 0xc06190 exited.
After the thread
Proxied main thread 0xa05c18 finished with return code 0. EXIT_RUNTIME=0 set, so
keeping main thread alive for asynchronous event operations.
Pthread 0xa05c18 exited.

▍Rust


В отличие от Emscripten в Rust нет специализированной сквозной веб-цели сборки, вместо этого он предоставляет цель wasm32-unknown-unknown для обобщенного вывода wasm.

Если wasm планируется использовать в веб-среде, то любое взаимодействие с JavaScript API передается внешним библиотекам и инструментам вроде wasm-bingden и wasm-pack. К сожалению, это означает, что стандартная библиотека не знает о веб-воркерах, и стандартные API, такие как std:thread, при компиляции в wasm работать не будут.

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

Что касается Rust, то самым популярным выбором для параллельной обработки данных в нем является библиотека Rayon. Она позволяет брать цепочки методов в стандартных итераторах и, как правило путем изменения всего одной строки, преобразовывать их так, чтобы они выполнялись на всех доступных потоках параллельно, а не последовательно. К примеру:

pub fn sum_of_squares(numbers: &[i32]) -> i32 {
  numbers

  .par_iter()
  .map(|x| x * x)
  .sum()
}

После этого небольшого изменения код разделит входные данные, вычислит x * x и частичные суммы в параллельных потоках, а в конце сложит эти частичные суммы вместе.

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

wasm-bindgen-rayon подключается к этим хукам для создания потоков wasm в виде веб-воркеров. Чтобы использовать эту библиотеку, добавьте ее в качестве зависимости и следуйте настройке, описанной в документации. Пример выше получится таким:

pub use wasm_bindgen_rayon::init_thread_pool;

#[wasm_bindgen]
pub fn sum_of_squares(numbers: &[i32]) -> i32 {
  numbers
  .par_iter()
  .map(|x| x * x)
  .sum()
}

После завершения сгенерированный JavaScript экспортирует дополнительную функцию initThreadPool. Эта функция создаст пул воркеров и будет переиспользовать их в течение жизненного цикла программы для любых многопоточных операций, выполняемых Rayon.

Этот механизм пула аналогичен ранее описанной опции -s PTHREAD_POOL_SIZE=… в Emscripten и для избежания взаимных блокировок также требует инициализации перед основным кодом:

import init, { initThreadPool, sum_of_squares } from './pkg/index.js';

// Стандартная инициализация wasm-bindgen.
await init();

// Инициализация пула потоков с их заданным числом 
// (если хотите использовать все ядра, передайте `navigator.hardwareConcurrency`).
await initThreadPool(navigator.hardwareConcurrency);

// ...теперь можно вызывать любые экспортированные функции как обычно 
console.log(sum_of_squares(new Int32Array([1, 2, 3]))); // 14

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

Ожидание может быть как очень коротким, так и весьма длинным, что будет зависеть от сложности итераторов и количества доступных потоков. Однако из соображений безопасности движки браузеров активно предотвращают блокирование основного потока, и такой код будет выдавать ошибку. Вместо этого следует создать воркера, импортировать в него код, сгенерированный wasm-bindgen, и представить его API основному потоку с помощью библиотеки вроде Comlink.

Посмотрите на GitHub пример wasm-bindgen-rayon, где продемонстрировано:


Реальные случаи использования


Мы активно используем потоки wasm в Squoosh.app для сжатия изображений на стороне клиента – в частности, для форматов вроде AVIF (C++), JPEG-XL (C++), OxiPNG (Rust) и WebP v2 (C++). Благодаря одной только многопоточности мы наблюдаем устойчивый прирост скорости в 1.5-3 раза (конкретный показатель зависит от кодека) и смогли достичь даже больших успехов, совместив потоки WebAssembly с WebAssembly SIMD.

Еще одним примечательным сервисом, использующим многопоточность WebAssembly в своей веб-версии, является Google Earth.

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

Есть и много других прекрасных примеров использования потоков WebAssembly. Рекомендую ознакомиться с предложенным примером с GitHub и ожидаю, что вы также дополните веб-мир своими многопоточными приложениями и библиотеками.

Комментарии (20)


  1. kovserg
    05.08.2021 17:45
    +3

    И сколько теперь мегахешей можно получать с каждого зашедшего на сайт?


  1. DCNick3
    06.08.2021 16:52

    А как вы распространяете получившиеся после emscripten модули для использования другим JS-кодом? Последний раз, когда я смотрел, инструментов для C/C++ модулей практически не было. Есть ли что-то наподобие wasm-pack для C/C++, хотя бы могущее в паковку модулей и их использование в webpack?


    1. Alexufo
      11.08.2021 16:17

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


  1. vit1251
    09.08.2021 00:12

    Праивльно ли я понимаю, что WASM это еще одна попытка зайти в байт-код на стороне пользоватлея? Почему это должно в этот раз произойти? Напомню, что существовал Java Applets (с которым я когда-то делал приложение для рисования диаграм), а позднее был SilverLight, Macromedia Flash и на самом деле я думаю, что еще много всего вроде NPAPI и т.д. Почему на этот раз должно взлететь? Теперь W3C не будет ставить палки в колеса и помогать стандарту развиваться? А это вроде как выглядит не очень конкурентно со стороны свободного сцентра стандартизации? С другой стороны почему бы и нет... так как с каждым днем не видно сильных игроков на стороне универсальных GUI для ОС общего назначения.


    1. dsrk_dev
      11.08.2021 01:16

      в этот раз все браузеры уже реализовали поддержку WebAssembly


      1. vit1251
        11.08.2021 18:14
        -2

        В этот раз в разработке нет основного недостатка (NIH) на мой взгляд. Именно по этому WASM-у и дали зеленый свет. Если моя догадка верная, то очень печально это осознавать: союз W3C и все эти альтруисты по сути просто выпинали неудобный им продукты с условного "рынка".


    1. Alexufo
      11.08.2021 16:19

      Вам нужно почитать причины по которым WebAssemly все таки создавался, все что вы перечислили ровно там и разобраны. Начнем с того, что код выполняется строго в песочнице.


      1. vit1251
        11.08.2021 17:59
        -3

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

        Вы утверждаете, что код работающий в Java Applet и Silverlight выполнялись не в песочнице виртуальной машины?


        1. Alexufo
          11.08.2021 18:28
          +2

          Нет тут ничего оскорбительного, вопрос безопасности стоял, как вы можете догадаться, на первом месте. Явааплеты как и флеш так и Silverlight не выполнялись в такой изолированной среде, потому что могут сами порождать свои процессы и иметь доступ к апи браузера да и не только браузера. WebAssembly работает только в случае вызова его js и общается с браузером он только через js. Он не может сделать ничего что не может делать js.


          1. vit1251
            11.08.2021 18:44
            -2

            Явааплеты как и флеш так и Silverlight не выполнялись в такой изолированной среде, потому что могут сами порождать свои процессы и иметь доступ к апи браузера да и не только браузера. WebAssembly работает только в случае вызова его js и общается с браузером он только через js. Он не может сделать ничего что не может делать js.

            Разве Java Applet может порождать процессы на пользовательском окружении без яновго на это разрешения? На сколько я помню для этого нужно запросить дополнительное разрешение у пользователя, а в этом сейчас и есть главное ограничение и достоинство WASM по вашему мнению?

            Хорошо я понял Вашу позицию и видимо какую-то веру (скорее всего производственную вовлеченность) в то что одна технология была уязвима, а другая сейчас будет надежной и современной за счет использования видимо JSON и ограниченной по возможностям виртуальной JS мышины. Кстати напомню, что Node.js отлично запускает внешние процессы, так что в некоторых реализациях так же можно запускать внешние процессы.


            1. Alexufo
              11.08.2021 18:58
              +2

              Разве Java Applet может порождать процессы на пользовательском окружении без яновго на это разрешения?

              Кажется с яваапплетами такое творилось, что разрешения было вообще не нужно.


              васм не может вызывать сам свой код. Только js, который дергает его каждый раз где ему это нужно.
              Хорошо я понял Вашу позицию и видимо какую-то веру (скорее всего производственную вовлеченность) в то что одна технология была уязвима, а другая сейчас будет надежной

              Дело в архитектуре, в webAssembly она совершенно другая. Ничего нового по сути в браузер не добавляется, кроме среды исполнения, которая может взломать браузер ровно так же как и любой сайт, использующий js.

              В долгосрочке дать васму больше полномочий к браузерному API без обращения к js.

              Кстати напомню, что Node.js отлично запускает внешние процессы, так что в некоторых реализациях так же можно запускать внешние процессы.

              У ноды написано дополниельное API, поэтому это нода а не браузер.
              Посмотреть как нода работает в браузере можно по этой ссылке
              stackblitz.com/fork/node
              npm работает
              Только все необходимое апи для работы ноды переписано на js. (типа обращения к сайтам)


              1. vit1251
                11.08.2021 19:46
                -2

                Кажется с яваапплетами такое творилось, что разрешения было вообще не нужно.

                Ну тут я не подскажу вполне вероятно, что какие-то сочетания версий и программного обеспечения могли давать возможность уязвимостей, но как я вижу в последних версиях полным полно каких-то механизмов защиты https://docs.oracle.com/en/java/javase/14/security/java-security-overview1.html#GUID-C6D250FC-F147-4284-A6BF-8384DFD39DA6

                Дело в архитектуре, в webAssembly она совершенно другая. Ничего нового по сути в браузер не добавляется ...

                Так какая разница виртуальную машину переиспользовать у браузера или прлепить движки от C# или JVM? Почему доверия Google больше чем разработчику Windows или Oracle? Единственный профит, который я тут вижу, так это переносимость платформы, которой не обладает по хорошему ни JVM и ни .NET. А уязвимости будут что в WASM, что в любой другой платформе это сегодня уже всем понятно, что делать без ошибок люди не могут.


                1. Alexufo
                  11.08.2021 19:58
                  +2

                  в последних версиях


                  Емнип, поддержка java аплетов выпелена из браузеров помоему абсолютно принудительно и уже довольно давно.

                  Так какая разница виртуальную машину переиспользовать у браузера или прлепить движки от C# или JVM? Почему доверия Google больше чем разработчику Windows или Oracle?

                  васм позволяет отвязаться от языка и выполнять и c# или java в браузере, почти любую кодовую базу вашего уже написанного приложения. Автокад кажется так перенес своего монстра в браузер.

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

                  Уязвимости это про архитектуру. Все показывает только время. Архитектурно тут все очень безопасно.


                  1. vit1251
                    12.08.2021 11:24

                    Емнип, поддержка java аплетов выпелена из браузеров помоему абсолютно принудительно и уже довольно давно.

                    Да, действительно на сайте Java была новость https://www.java.com/ru/download/help/firefox_java.html о том, что NPAPI больше не соответствует профилям безопастности браузера, но запуск приложений через "Web Start" вроде работает. Приложение будет загружено и выполнено на целевой машине в JVM. Просто непонятно зачем нужен браузер как Canvas для рисования или какие-то другие преимущества?

                    Автокад кажется так перенес своего монстра в браузер.

                    Вот это выглядит как ползеная для бизнеса возможность собрать уже существующее приложение на C/C++, C#, Java и предоставить на любую платформу в виде байткода работающего в виртуальной машине, но скорее всего нужно будет писать промежуточный слой для того же GUI и сегодня полным полно уже готовых виртуальных машин JVM, .NET их не пишет разве что ленивый (кстати о ленивых, а что там для кросплатформы в macOS?). Странно только зачем использовать браузер как уже ранее говорили, что для Java есть JNLP или "Web Start" и думаю, что для C# есть что-то подобное. Чувствую, что корпорации вроде Google/Mozilla решили выйти на рынок настольных приложений обойдя все эти инновационные .NET, Cocoa, WPF, WindowsForms, GTK и прочие GUI Toolkit-ы и VM-ки предварительно выпилив из браузеров и даже из ОС потенциальных "конкурентов".

                    васм не может вызывать сам свой код

                    Не совсем понятно о чем тут речь? В языке нет eval или о чем идет речь? Нельзя создать буфер с байткодом и передать на него управление?

                    Архитектурно тут все очень безопасно.

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


                    1. Alexufo
                      12.08.2021 14:59
                      +1

                      Просто непонятно зачем нужен браузер как Canvas для рисования или какие-то другие преимущества?

                      Общий вопрос почему веб заменяет десктопные приложения.
                      но скорее всего нужно будет писать промежуточный слой для того же GUI

                      Конечно. Хочешь в веб, надо поковыряться.

                      что для C# есть что-то подобное.

                      Ага, Блазор.
                      dotnet.microsoft.com/apps/aspnet/web-apps/blazor

                      Нельзя создать буфер с байткодом и передать на него управление?

                      Инициировать выполнение кода васм может только если его дёрнет js. Нельзя на васме породить какой-то новый процесс, вызвать самостоятельно какой-то метод. Кажется там байткод просто дергается через промисы. То есть сам свой байткод он не умеет вызывать без js.
                      Эту маркетинговую сказку рассказывает каждый производитель своего продукта, но смотрите сколько в тем же браузере было уязвимостей.


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


                      1. vit1251
                        13.08.2021 10:43

                        Общий вопрос почему веб заменяет десктопные приложения.

                        Экономический для компании не выгодно писать с нуля три приложения для Widnows, macOS и не дай бог ещё искать фанатиков писать приложение для Linux. Так вот и выходит, что можно взять и сделать что-то на электроне. Правда мне вот интетесно сравнивал ли затраты кто-то и действительно выходит дешевле?

                        Редко когда решают писать с нуля, а если есть кодовая база, то можно сделать запуск с использованием этих плюшек вроде Web Start. Хотя я уже далек от этих стеков и не знаю использует их кто-то сегодня.

                        Конечно. Хочешь в веб, надо поковыряться.

                        Это почти в каждой технологии. Думаю, что запуск через JNLP тоже будет для компании стоить денег, так как там возникнут какие-то свои требования и проблемы. Так что затраты будут при любом переходе. Бесплатный сыр только в мышеловке. Вопрос стоимости каждой "новой" технологии и ее потенциальных возможностей.

                        Вот Сафари ублюдки, они тормозят внедрение васма, они боятся потеряться рынок

                        Ну подождем и посмотрим как они прокомментирую ситуацию. Я думаю, что после того как они сделали Swift в догонку к Java, C# они теперь долго будут еще рассказывать о преимуществах своего изделия. В целом конечно WASM на мой взгляд хочет урвать рынок десктоп приложений как я понимаю и постепенно стать уравнивателем за счет своей аудитории пользователей браузеров. Движение любопытное, но почему-то вспоминаю ребят из QT, которые в свое время все это уже делали, а раньше пионером была Java с ее наш код работает везде. Просто интересно почему WASM считает, что именно у них это выйдет?


                      1. Alexufo
                        13.08.2021 13:06

                        wasm ничего не считает, просто веб расширяет возможности, речь не только про одну кодовую базу но и удобство доставки обновлений.
                        Вариант работы с распознаванием жестов.
                        fingerspelling.xyz/game


                    1. mayorovp
                      30.08.2021 11:46

                      Web Start — это вообще не про исполнение в браузере, это про скачивание и запуск.


                      1. vit1251
                        30.08.2021 21:40

                        Возможно это по какой-то причине для вас имеет какое-то очень важное значение (структура и компонентная модель той или иной технологии), но я тут говорю в целом о подходе. Подход скачать байт код и запустить в виртуальной машине вроде уже много раз предлагался рынку и Java, .NET, Macromedia, а позднее Adobe. В целом думаю, что это просто борьба технологических компаний, но меня в данном случае интеерсует не конкретная реализация (думаю что и через 20-30 лет будет какой-то новый пионер и так же задушит этот WebAssembly), а скорее ошибка технологических компаний и крупных игроков? Где они ошиблись создавая свои решения?


  1. Alexufo
    12.08.2021 14:58

    del