Домашняя » кодирование » Введение в общую память в JavaScript

    Введение в общую память в 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 может помочь вам с некоторыми трудностями, уменьшая непредсказуемый характер чтения / записи из общей памяти.