Передача данных между потоками: Transferable, SharedArrayBuffer

ONNX Runtime Web (ORT Web) предоставляет возможность запуска моделей машинного обучения в браузере и в Node.js. Основной способ установки — через npm:

npm install onnxruntime-web

Подключение в JavaScript осуществляется через импорт:

import * as ort from 'onnxruntime-web';

Для работы с WebAssembly (WASM) и WebGL доступны различные бэкенды, которые позволяют оптимизировать производительность на различных устройствах.


Создание сессии и загрузка модели

Сессия ONNX Runtime Web создается через конструктор InferenceSession. Для веб-приложений модель можно загрузить напрямую с сервера или из локального файла:

const session = await ort.InferenceSession.create('model.onnx', {
  executionProviders: ['wasm'] // 'webgl' для ускорения через GPU
});

Ключевой параметр executionProviders определяет используемый движок выполнения. Выбор между WASM и WebGL зависит от требуемой производительности и доступных ресурсов устройства.


Передача данных между потоками

Для эффективной работы с большими данными в браузере часто требуется передавать массивы между потоками без копирования. Здесь важную роль играют объекты Transferable и SharedArrayBuffer.

Transferable объекты

Transferable объекты позволяют перемещать память из одного потока в другой без дублирования. Основной пример — ArrayBuffer:

const buffer = new ArrayBuffer(1024);
worker.postMessage(buffer, [buffer]);
console.log(buffer.byteLength); // 0, память передана

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

ORT Web поддерживает передачу данных модели через Transferable объекты. Например, входные тензоры можно упаковать в Float32Array и передать в воркер:

const inputTensor = new ort.Tensor('float32', new Float32Array([1, 2, 3, 4]), [2, 2]);
worker.postMessage({ tensor: inputTensor.data.buffer }, [inputTensor.data.buffer]);

SharedArrayBuffer для совместного доступа

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

const sharedBuffer = new SharedArrayBuffer(1024 * 4);
const sharedArray = new Float32Array(sharedBuffer);

sharedArray[0] = 42;
worker.postMessage({ buffer: sharedBuffer });

Использование SharedArrayBuffer важно для сценариев с большим объемом данных, где необходимо минимизировать накладные расходы на копирование.


Интеграция с ONNX Runtime Web

ORT Web поддерживает работу с SharedArrayBuffer и Transferable объектами для входных и выходных тензоров. Пример создания тензора с SharedArrayBuffer:

const sharedData = new SharedArrayBuffer(Float32Array.BYTES_PER_ELEMENT * 4);
const inputTensor = new ort.Tensor('float32', new Float32Array(sharedData), [2, 2]);
const feeds = { input: inputTensor };

const results = await session.run(feeds);
const outputTensor = results.output;
console.log(outputTensor.data);

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


Асинхронная обработка данных

Для оптимальной производительности часто применяют воркеры:

const worker = new Worker('worker.js');

worker.onmess age = (event) => {
  const outputTensor = new ort.Tensor('float32', new Float32Array(event.data.buffer), [2, 2]);
  console.log(outputTensor.data);
};

const inputData = new Float32Array([1, 2, 3, 4]);
worker.postMessage({ buffer: inputData.buffer }, [inputData.buffer]);

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


Практические рекомендации

  • Для небольших данных достаточно обычных ArrayBuffer с Transferable объектами.
  • Для больших массивов, требующих одновременного доступа из нескольких потоков, предпочтительнее использовать SharedArrayBuffer.
  • В случаях интенсивного GPU-вычисления через WebGL данные лучше предварительно загружать и конвертировать в нужный формат в отдельном воркере.
  • Всегда контролировать синхронизацию при работе с SharedArrayBuffer, чтобы избежать гонок данных.

Эти методы позволяют максимально эффективно использовать ONNX Runtime Web в высоконагруженных браузерных приложениях.