Введение в общую память в JavaScript

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

Разве это не звучит мило? Ну, почти. В этом посте мы увидим, как использовать разделяемую память в JavaScript и как решить, действительно ли вы этого хотите.

Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)

Преимущества и недостатки разделяемой памяти
Мы используем веб-работников для создания потоков в JavaScript. API Web Workers позволяет нам создавать рабочие потоки, которые можно использовать для выполнения кода в фоновом режиме, чтобы основной поток мог продолжать выполнение, возможно, обрабатывая события пользовательского интерфейса, гарантируя отсутствие зависания пользовательского интерфейса.

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

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

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

Но совместное использование является заботой, и многим потокам также может понадобиться одновременно просматривать одни и те же данные и изменять их. Таким образом, запрет обмена является большой нет-нет. Это где 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 ();
}

Используя приведенный выше код, мы получаем следующий вывод в консоли:

[worker]

Данные, полученные из основного потока: 9

Вы можете прочитать мой вышеупомянутый пост о веб-работниках для полного объяснения кода вышеупомянутых фрагментов.

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

Теперь, если мы изменим данные, они будут выглядеть обновленными на принимающей стороне? Посмотрим:

const w = новый работник (‘worker.js’);
var n = 9;
w.postMessage (п);
n = 1;

Как и ожидалось, данные имеют не был обновлен:

[worker]

Данные, полученные из основного потока: 9

В любом случае, с чего бы это? Это просто клон, отправленный рабочему из основного скрипта.
Веб-работники с Общая память
Теперь мы будем использовать объект SharedArrayBuffer в том же примере. Мы можем создать новый экземпляр SharedArrayBuffer, используя ключевое слово new. Конструктор принимает один параметр; значение длины в байтах, определяющее размер буфера.

const w = новый работник (‘worker.js’);
buff = new SharedArrayBuffer (1);
var arr = new Int8Array (buff);
/ * настройка данных * /
прибытие[0] = 9;
/ * отправка буфера (копии) работнику * /
w.postMessage (положительный эффект);

Обратите внимание, что объект SharedArrayBuffer представляет только область общей памяти. Чтобы увидеть и изменить двоичные данные, нам нужно использовать соответствующую структуру данных ( TypedArray или DataView объект).

В приведенном выше файле index.html создается новый SharedArrayBuffer, длина которого составляет всего один байт. Затем новый Int8Array, который является одним из типов объектов TypedArray, используется для установки данных на «9» в предоставленном байтовом пространстве.

onmessage = (e) => {
  var arr = new Int8Array (e.data);
  console.group (»[worker]«);
  console.log (‘Данные получены из основного потока:% i’, обр.[0]);
  console.groupEnd ();
}

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

Ожидаемое значение появляется в консоли из рабочего потока, и это именно то, что мы хотели:

[worker]

Данные, полученные из основного потока: 9

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

const w = новый работник (‘worker.js’),
buff = new SharedArrayBuffer (1);
var arr = new Int8Array (buff);
/ * настройка данных * /
прибытие[0] = 9;
/ * отправка буфера (копии) работнику * /
w.postMessage (положительный эффект);
/ * изменение данных * /
прибытие[0] = 1;
И, как вы можете видеть ниже, обновление отражается внутри рабочего!

[worker]

Данные, полученные из основного потока: 1

Но код также должен работать наоборот: когда значение в работнике изменяется сначала, его также необходимо обновлять, когда оно печатается из основного потока.

В этом случае наш код выглядит так:

onmessage = (e) => {
  var arr = new Int8Array (e.data);
  console.group (»[worker]«);
  console.log (‘Данные получены из основного потока:% i’, обр.[0]);
  console.groupEnd ();
  / * изменение данных * /
  прибытие[0] = 7;
  / * отправка в основную ветку * /
  PostMessage ( ”);
}

Данные изменяются на рабочем месте, и в главный поток отправляется пустое сообщение, сигнализирующее, что данные в буфере были изменены и готовы к выводу основного потока.

const w = новый работник (‘worker.js’),
buff = new SharedArrayBuffer (1);
var arr = new Int8Array (buff);
/ * настройка данных * /
прибытие[0] = 9;
/ * отправка буфера (копии) работнику * /
w.postMessage (положительный эффект);
/ * изменение данных * /
прибытие[0] = 1;
/ * печать данных после того, как работник их изменил * /
w.onmessage = (e) => {
  console.group (»[main]«);
  console.log (‘Обновлены данные, полученные из рабочего потока:% i’, обр.[0]);
  console.groupEnd ();
}

И это тоже работает! Данные в буфере совпадают с данными внутри рабочего.

[worker]

Данные, полученные из основного потока: 1
[main]
Обновлены данные, полученные из рабочего потока: 7

Значение отображается обновленным в обоих случаях; и основной, и рабочий потоки просматривают и изменяют одни и те же данные.
Заключительные слова
Как я упоминал ранее, использование разделяемой памяти в JavaScript не лишено недостатков. Разработчики должны убедиться, что последовательность выполнения происходит в соответствии с прогнозом, и нет двух потоков, стремящихся получить те же данные, потому что никто не знает, кто получит трофей.

Если вас больше интересует общая память, ознакомьтесь с документацией атомная энергетика объект. Объект Atomics может помочь вам справиться с некоторыми трудностями, уменьшив непредсказуемый характер чтения / записи из общей памяти.

Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *