Введение в общую память в JavaScript
Общая память это расширенная функция JavaScript, которую могут использовать потоки (параллельно выполняемые части процесса). Разделение памяти означает не имея проблем с передачей обновленных данных между потоками и все потоки могут получать доступ и обновлять одни и те же данные в общей памяти.
Разве это не звучит прекрасно? Ну, почти. В этом посте мы увидим как использовать разделяемую память в JavaScript и как решить, если это то, что вы действительно хотите сделать.
Преимущества и недостатки разделяемой памяти
Мы используем веб-работники в создавать темы в JavaScript. API Web Workers позволяет нам создавать рабочие потоки, которые можно использовать для выполнить код в фоновом режиме так что основной поток может продолжить выполнение, возможно, обрабатывая события пользовательского интерфейса, гарантируя отсутствие зависания пользовательского интерфейса.
Рабочие темы работать одновременно с основным потоком и друг с другом. Такое одновременное выполнение разных частей задачи экономит время. Вы заканчиваете быстрее, но у этого также есть свой собственный набор проблем.
Убедиться, что каждая нить получает необходимые ресурсы и своевременно общается друг с другом это задача сама по себе, где неудача может привести к неожиданному результату. Или если один поток изменяет данные, а другой читает в то же время, как вы думаете, что увидит другая нить? Обновленные или старые данные?
Однако веб-работникам не так легко облажаться. Во время их общения с помощью сообщений данные, которые они посылают друг другу, не оригинал, а копия, это означает, что они не доля одни и те же данные. Oни передавать копии данных друг другу при необходимости.
Но совместное использование - это забота, и многим потокам может потребоваться одновременно просматривать одни и те же данные и изменять их. Так, запрещение обмена является большой нет-нет. Это где SharedArrayBuffer
объект входит в картину. Это позволит нам делиться двоичными данными между несколькими потоками.
SharedArrayBuffer
объект
Вместо того, чтобы передавать копии данных между потоками, мы передать копии SharedArrayBuffer
объект. SharedArrayBuffer
объект указывает на память, в которой хранятся данные.
Так что, даже когда копии SharedArrayBuffer
передаются между потоками, они все по-прежнему будут указывать на одну и ту же память где сохранены исходные данные. Темы, таким образом, могут просматривать и обновлять данные в той же памяти.
Веб-работники без Общая память
Чтобы увидеть, как работает веб-работник без использования общей памяти, мы создать рабочий поток а также передать ему некоторые данные.
index.html
файл содержит основной сценарий внутри тег, как вы можете видеть это ниже:
const w = новый работник ('worker.js'); var n = 9; w.postMessage (п);
worker.js
файл несет рабочий скрипт:
onmessage = (e) => console.group ('[worker]'); console.log («Данные получены из основного потока:% i», e.data); console.groupEnd ();
Используя код выше, мы получаем следующее вывод в консоль:
[работник] Данные, полученные из основного потока: 9
Вы можете прочитать мой вышеупомянутый пост о веб-работниках для полного объяснения кода приведенных выше фрагментов..
Пока имейте в виду, что данные отправляется туда и обратно между темами с использованием PostMessage ()
метод. Данные получил на другой стороне сообщение
обработчик события, в качестве значения события данные
имущество.
Теперь, если мы изменить данные будет ли он обновляться на принимающей стороне? Посмотрим:
const w = новый работник ('worker.js'); var n = 9; w.postMessage (п); n = 1;
Как и ожидалось, данные имеют не был обновлен:
[работник] Данные, полученные из основного потока: 9
В любом случае, с чего бы это? Это просто клон, отправленный рабочему из основного скрипта.
Веб-работники с Общая память
Теперь мы будем использовать SharedArrayBuffer
объект в том же примере. Мы можем создать новый SharedArrayBuffer
экземпляр по с использованием новый
ключевое слово. Конструктор принимает один параметр; значение длины в байтах, указание размера буфера.
const w = новый работник ('worker.js'); buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * данные настройки * / arr [0] = 9; / * отправка буфера (копии) работнику * / w.postMessage (buff);
Обратите внимание, что SharedArrayBuffer
объект представляет только общую область памяти. к увидеть и изменить двоичные данные, нам нужно использовать соответствующую структуру данных ( TypedArray
или DataView
объект).
в index.html
файл выше, новый SharedArrayBuffer
создается только длиной в один байт. Затем новый Int8Array
, который является одним из типов TypedArray
объекты, используется для установить данные в “9” в предоставленном байтовом пространстве.
onmessage = (e) => var arr = new Int8Array (e.data); console.group ( '[рабочий]'); console.log ('Данные получены из основного потока:% i', arr [0]); console.groupEnd ();
Int8Array
также используется в работнике, чтобы просмотреть данные в буфере.
ожидаемое значение появляется в консоли из рабочего потока, который именно то, что мы хотели:
[работник] Данные, полученные из основного потока: 9
Теперь давайте обновить данные в главном потоке чтобы увидеть, если изменение отражается на работнике.
const w = new Worker ('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 ( '[рабочий]'); console.log ('Данные получены из основного потока:% i', arr [0]); console.groupEnd (); / * изменение данных * / arr [0] = 7; / * отправка сообщений в основную ветку * / postMessage (");
данные изменены в работнике и пустое сообщение размещено в главной теме сигнализация того, что данные в буфере были изменены и готовы для основного потока, который будет выведен.
const w = new Worker ('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 ();
И это тоже работает! Данные в буфере совпадают с данными внутри рабочего.
[работник] Данные, полученные из основного потока: 1 [основной] Обновленные данные, полученные из рабочего потока: 7
Значение обновляется в обоих случаях; как основной, так и рабочий потоки просматривают и изменяют одни и те же данные..
Заключительные слова
Как я упоминал ранее, использование разделяемой памяти в JavaScript не без минусов. Разработчики должны убедиться, что последовательность выполнения происходит в соответствии с прогнозом и никакие два потока не участвуют в гонке за одинаковыми данными, потому что никто не знает, кто возьмет трофей.
Если вас больше интересует общая память, ознакомьтесь с документацией атомная энергетика
объект. Объект Atomics может помочь вам с некоторыми трудностями, уменьшая непредсказуемый характер чтения / записи из общей памяти.