Skip to main content

Що робить SharedArrayBuffer?

Що таке SharedArrayBuffer

SharedArrayBuffer - це спеціальний тип буфера, який:

  • містить сирі двійкові дані (байти);
  • може бути розділений між різними потоками (наприклад, Web Worker і основним потоком);
  • дозволяє одночасно читати й писати в ту саму пам'ять;
  • не копіює дані при передачі - передається посилання на ту саму ділянку пам'яті.

Відмінність від звичайного ArrayBuffer

ВластивістьArrayBufferSharedArrayBuffer
Використовується кимОдним потокомКількома потоками
При передачі воркеруКопіюється або передається через transfer (стає недоступним у вихідному потоці)Розділяється - обидва потоки бачать ту саму пам'ять
Можна використовувати AtomicsНіТак (для безпечної синхронізації)
ПотокобезпекаНе потрібнаПотрібна (через Atomics)

Приклад: спільний буфер між потоками

1. Основний потік (main.js)

javascript
// Створюємо спільний буфер на 4 байти (Int32 = 4 байти) const sharedBuffer = new SharedArrayBuffer(4); // Обгортаємо його в типізований масив const sharedArray = new Int32Array(sharedBuffer); sharedArray[0] = 0; // початкове значення // Створюємо воркер і передаємо спільний буфер const worker = new Worker('worker.js'); worker.postMessage(sharedBuffer); // Очікуємо змін setInterval(() => { console.log('Main thread value:', sharedArray[0]); }, 1000);

2. Воркер (worker.js)

javascript
onmessage = (e) => { const sharedArray = new Int32Array(e.data); // Збільшуємо значення кожні 500 мс setInterval(() => { Atomics.add(sharedArray, 0, 1); // атомарне приростання }, 500); };

Результат:

javascript
Main thread value: 0 Main thread value: 2 Main thread value: 4 Main thread value: 6 ...

SharedArrayBuffer забезпечує спільну пам'ять, а Atomics гарантує потокобезпеку (без гонок даних).

Навіщо потрібен Atomics

Оскільки кілька потоків можуть одночасно читати й записувати одну й ту саму комірку пам'яті, без синхронізації можуть виникати гонки (race conditions).

Для цього існує об'єкт Atomics, який надає атомарні операції:

МетодЩо робить
Atomics.add(typedArray, index, value)Додає значення атомарно
Atomics.sub()Віднімає атомарно
Atomics.and() / or() / xor()Побітові атомарні операції
Atomics.load() / Atomics.store()Безпечне читання/запис
Atomics.exchange()Змінює значення і повертає старе
Atomics.compareExchange()Змінює, якщо поточне збігається з очікуваним
Atomics.wait() / Atomics.notify()Дозволяє "приспати" потік, поки значення не зміниться (лише у воркерах)

Приклад: синхронізація за допомогою Atomics.wait / Atomics.notify

javascript
// main.js const sharedBuffer = new SharedArrayBuffer(4); const sharedArray = new Int32Array(sharedBuffer); const worker = new Worker('worker.js'); worker.postMessage(sharedBuffer); // Через 2 секунди "розбудимо" воркер setTimeout(() => { console.log('Main: notify worker'); Atomics.store(sharedArray, 0, 1); Atomics.notify(sharedArray, 0, 1); }, 2000);
javascript
// worker.js onmessage = (e) => { const sharedArray = new Int32Array(e.data); console.log('Worker: waiting...'); Atomics.wait(sharedArray, 0, 0); // чекає, поки значення не зміниться console.log('Worker: woken up, value:', sharedArray[0]); };

Тут воркер буквально "спить", поки основний потік не "розбудить" його. Це дає реальну багатопотоковість (координацію між потоками JS).

Де використовується SharedArrayBuffer

СценарійЗастосування
Web WorkersПередача великих даних без копіювання
Багатопотокові обчисленняПаралельна обробка матриць, графіки, фізики
Ігри та симуляціїОновлення стану світу в кількох потоках
Machine Learning / WASMTensorFlow.js, WebAssembly, OpenCV використовують SharedArrayBuffer
Обробка відео / аудіоСпільне використання буферів між потоками
Шина обміну між воркерамиМиттєва передача даних без серіалізації JSON

Безпека й обмеження (CORS / COOP / COEP)

Через ризики вразливостей Spectre браузери вмикають SharedArrayBuffer лише в ізольованих контекстах (Cross-Origin Isolation).

Щоб SharedArrayBuffer працював у браузері, потрібно виставити правильні заголовки:

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

І переконатися, що всі ресурси (скрипти, воркери) також сумісні з цим режимом.

Приклад: увімкнення Cross-Origin Isolation

Для dev-сервера (наприклад, Vite чи Express):

javascript
app.use((req, res, next) => { res.setHeader("Cross-Origin-Opener-Policy", "same-origin"); res.setHeader("Cross-Origin-Embedder-Policy", "require-corp"); next(); });

Тепер браузер дозволить використовувати SharedArrayBuffer.

Підсумок

ВластивістьОпис
Що робитьРозділяє пам'ять між потоками без копіювання
Де працюєУ Web Workers і Node.js (worker_threads)
ВимагаєAtomics для синхронізації
БезпекаЛише при увімкненому COOP/COEP
Типові сценаріїПаралельні обчислення, кеш, рендеринг, WebAssembly
Аналог у C/C++Спільна пам'ять (shared memory) між потоками

Головна ідея:

SharedArrayBuffer дає JavaScript можливість реального паралелізму

  • кілька потоків можуть читати й писати в одну пам'ять одночасно, а Atomics при цьому забезпечує коректність і синхронізацію.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.