Вступ до спільної пам'яті у JavaScript
Спільна пам'ять є розширеною функцією JavaScript, що потоки (одночасно виконувані частини процесу) можуть використовуватись. Обмін засобами пам'яті не мають проблем з передачею оновлених даних між потоками і всі потоки можуть отримувати доступ і оновлювати ті ж дані в спільній пам'яті.
Хіба це не чудово звучить? Ну, майже. У цьому пості ми побачимо як використовувати спільну пам'ять у JavaScript і як вирішити, чи дійсно ви хочете це зробити.
Переваги та недоліки спільної пам'яті
Ми використовуємо веб-працівників до створювати теми у JavaScript. API Web Workers дозволяє створювати робочі потоки, до яких можна користуватися виконати код у фоновому режимі так що основний потік вільний для продовження його виконання, можливо, обробляючи події інтерфейсу користувача, забезпечуючи відсутність заморожування UI.
Робочі нитки Виконати одночасно з основним потоком і один з одним. Таке одночасне виконання різних частин завдання економія часу. Ви закінчуєте швидше, але він також має свій власний набір проблем.
Переконавшись, що кожен потік отримує необхідні ресурси і своєчасно спілкується один з одним це завдання само по собі, де невдача може призвести до дивного результату. Або, якщо один потік змінює дані, а інший читає в той самий час, що ви думаєте, що інший потік побачить? Оновлені або старі дані?
Тим не менш, веб-працівників не так просто заплутатися. Під час спілкування за допомогою повідомлень дані, які вони передають один одному, є не оригінал, а копія, що вони не мають акції ті ж дані. Вони передавати копії даних один одному коли потрібно.
Але спільний доступ є дбайливим, і для декількох потоків може знадобитися одночасно переглядати ті ж дані і змінювати їх. Тому, заборона спільного використання є великим ні-ні. Ось де SharedArrayBuffer
об'єкт приходить в картину. Це дозволить нам обміну двійковими даними між декількома потоками.
The SharedArrayBuffer
об'єкт
Замість того, щоб передавати копії даних між потоками, ми передавати копії SharedArrayBuffer
об'єкт. A SharedArrayBuffer
об'єкт вказує на пам'ять, де зберігаються дані.
Отже, навіть коли копії SharedArrayBuffer
передаються між потоками, вони все ще вказуватиме на ту ж пам'ять де зберігаються вихідні дані. Нитки, таким чином, можуть переглядати та оновлювати дані в цій самій пам'яті.
Веб-працівники без спільної пам'яті
Щоб дізнатися, як веб-працівник працює без використання спільної пам'яті, ми створити робочий потік і передайте їй деякі дані.
The index.html
файл містить Головний сценарій всередині a тег, як ви можете бачити нижче:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n);
The worker.js
файл несе робочий сценарій:
onmessage = (e) => console.group ('[робочий]'); console.log ('Дані, отримані з основного потоку:% i', e.data); console.groupEnd ();
Використовуючи код вище, ми отримуємо наступне виводити в консоль:
[робочий] Дані, отримані з основного потоку: 9
Ви можете прочитати мій вищезгаданий пост на веб-роботах для повного пояснення коду вищезгаданих фрагментів.
Наразі майте на увазі, що дані є відправлені назад і вперед між потоками за допомогою postMessage ()
метод. Дані отримані на іншій стороні повідомлення
обробник подій, як значення події даних
власності.
Тепер, якщо ми змінити дані буде відображатися оновленим на кінці прийому? Давайте подивимося:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n); n = 1;
Як і очікувалося, даних ні оновлено:
[робочий] Дані, отримані з основного потоку: 9
Навіщо це було б? Його просто клон, надісланий працівнику з головного сценарію.
Веб-працівники с спільної пам'яті
Тепер ми будемо використовувати SharedArrayBuffer
об'єкт в цьому ж прикладі. Ми можемо створити нове SharedArrayBuffer
наприклад за допомогою новий
ключове слово. Конструктор приймає один параметр; a значення довжини в байтах, вказуючи розмір буфера.
const w = new Worker ('worker.js'); buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * налаштування даних * / arr [0] = 9; / * надсилання буфера (копіювання) працівника * / w.postMessage (buff);
Зверніть увагу, що a SharedArrayBuffer
об'єкт являє собою лише область загальної пам'яті. До бачити і змінювати двійкові дані, ми повинні використовувати відповідну структуру даних (a TypedArray
або a DataView
об'єкт.
В index.html
файл вище, новий SharedArrayBuffer
створено лише з довжиною в один байт. Потім новий Int8Array
, який є одним з видів TypedArray
об'єктів встановити дані “9” у наданому байті.
onmessage = (e) => var arr = new Int8Array (e.data); console.group ('[worker]'); console.log ('Дані, отримані з основного потоку:% i', arr [0]); console.groupEnd ();
Int8Array
використовується також у робочому, к переглядати дані в буфері.
The очікуване значення відображається в консолі з робочого потоку, що саме ми хотіли:
[робочий] Дані, отримані з основного потоку: 9
Тепер давайте оновлення даних в головному потоці щоб побачити, чи зміни відображаються у працівнику.
const w = новий працівник ('worker.js'), buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * налаштування даних * / arr [0] = 9; / * надсилання буфера (копіювання) працівника * / w.postMessage (buff); / * зміна даних * / arr [0] = 1;
І, як ви можете бачити нижче, оновлення відображає всередині робітника!
[робочий] Дані, отримані з основного потоку: 1
Але, код також потрібно працювати навпаки: коли значення у працівника змінюється спочатку, це також потрібно оновити коли він друкується з основного потоку.
У цьому випадку наш код виглядає так:
onmessage = (e) => var arr = new Int8Array (e.data); console.group ('[worker]'); console.log ('Дані, отримані з основного потоку:% i', arr [0]); console.groupEnd (); / * зміна даних * / arr [0] = 7; / * розміщення в головному потоці * / postMessage (");
The дані змінюються у працівнику і a порожнє повідомлення розміщено на головному потоці сигналізації про те, що дані в буфері були змінені і готові для виведення основного потоку.
const w = новий працівник ('worker.js'), buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * налаштування даних * / arr [0] = 9; / * надсилання буфера (копіювання) працівника * / w.postMessage (buff); / * зміна даних * / arr [0] = 1; / * друк даних після того, як працівник змінив його * / w.onmessage = (e) => console.group ('[main]'); console.log ('Оновлені дані, отримані від робочого потоку:% i', arr [0]); console.groupEnd ();
І це теж працює! Дані в буфері такі ж, як дані всередині працівника.
[worker] Дані, отримані з основного потоку: 1 [main] Оновлені дані, отримані від робочого потоку: 7
Значення відображається в обох випадках; як головні, так і робочі потоки переглядають та змінюють однакові дані.
Заключні слова
Як я вже згадував раніше, використання спільної пам'яті в JavaScript не без недоліків. Це до розробників, щоб переконатися, що Послідовність виконання відбувається як передбачено і ніякі дві нитки не гоняться, щоб отримати ті ж дані, тому що ніхто не знає, хто візьме трофей.
Якщо вас цікавить більше спільної пам'яті, подивіться на документацію Атоміка
об'єкт. The Об'єкт атомної техніки може допомогти вам з деякими труднощами, шляхом зменшення непередбачуваного характеру читання / запису з спільної пам'яті.