Введение в общую память в JavaScript
Общая память — это расширенная функция JavaScript, которую могут использовать потоки (параллельно выполняемые части процесса). Совместное использование памяти означает отсутствие проблем с передачей обновленных данных между потоками, и все потоки могут получать доступ и обновлять одни и те же данные в общей памяти.
Разве это не звучит мило? Ну, почти. В этом посте мы увидим, как использовать разделяемую память в JavaScript и как решить, действительно ли вы этого хотите.
Читайте также: Объектно-ориентированный JavaScript (OOJS): 3 способа создания экземпляров объектов
Программы для 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 может помочь вам справиться с некоторыми трудностями, уменьшив непредсказуемый характер чтения / записи из общей памяти.
Читайте также: Начало работы с обещаниями JavaScript
Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)