WedX - журнал о программировании и компьютерных науках

Нужны ли мьютексы в javascript?

Я видел эту ссылку: Реализация взаимного исключения в JavaScript. С другой стороны, я читал, что в javascript нет потоков, но что именно это означает?

Когда происходят события, где в коде они могут прерываться?

А если в JS нет потоков, нужно ли использовать в JS мьютексы или нет?

В частности, меня интересуют эффекты использования функций, вызываемых setTimeout() и XmlHttpRequest onreadystatechange для глобально доступных переменных.


Ответы:


1

Javascript определяется как реентерабельный язык, что означает, что пользователю не предоставляется доступ к потокам, в реализации могут быть потоки. Такие функции, как setTimeout() и асинхронные обратные вызовы, должны дождаться, пока обработчик сценариев спит, прежде чем они смогут работать.

Это означает, что все, что происходит в событии, должно быть завершено до того, как будет обработано следующее событие.

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

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

Хотя вы можете создать такое состояние гонки, очень легко предотвратить это в своем коде, поскольку каждая функция будет атомарной. Для фактического создания состояния гонки потребовалось бы много работы и несколько странных шаблонов кодирования.

24.09.2008
  • Создать это состояние гонки совсем несложно: например, у меня есть событие onkeyup в поле, которое запускает ajax-вызов БД для получения некоторых значений. Быстрый ввод данных может легко привести к неправильным результатам. 17.11.2017

  • 2

    Ответы на этот вопрос немного устарели, но верны на то время, когда они были даны. И все же правильно, если смотреть на клиентское приложение javascript, которое НЕ использует веб-работников.

    Статьи о веб-воркерах:
    многопоточность в javascript с использованием веб-мастеров
    Mozilla для веб-мастеров

    Это ясно показывает, что javascript через веб-воркеров имеет возможности многопоточности. Что касается вопроса, нужны ли мьютексы в javascript? Я не уверен в этом. Но этот пост stackoverflow кажется актуальным:
    Взаимное исключение для N асинхронных потоков

    22.02.2011
  • взрыв из прошлого, но я столкнулся с необходимостью мьютексов, когда несколько вкладок обращаются к одному и тому же локальному хранилищу 15.05.2014
  • WebWorkers не влияют на повторный вход, потому что они не разделяют состояние переменных и общаются только с основным потоком, передавая сообщения, которые запускают события. 01.08.2014

  • 3

    Как отмечает @william,

    вам может понадобиться мьютекс, если ваш код делает что-то там, где он ожидает, что значение не изменится между моментом запуска асинхронного события и моментом обратного вызова.

    Это можно обобщить дальше - если ваш код делает что-то там, где он ожидает монопольного управления ресурсом до разрешения асинхронного запроса, вам может потребоваться мьютекс.

    Простой пример: у вас есть кнопка, которая запускает вызов ajax для создания записи в серверной части. Вам может потребоваться немного кода, чтобы защитить вас от того, чтобы довольные пользователи щелкали мышью и создавали несколько записей. Есть несколько подходов к этой проблеме (например, отключить кнопку, включить при успешном использовании ajax). Вы также можете использовать простую блокировку:

    var save_lock = false;
    $('#save_button').click(function(){
        if(!save_lock){
            //lock
            save_lock=true;
            $.ajax({
                success:function()
                    //unlock
                    save_lock = false;  
                }
            });
        }
    }
    

    Я не уверен, что это лучший подход, и мне было бы интересно посмотреть, как другие обрабатывают взаимное исключение в javascript, но, насколько мне известно, это простой мьютекс, и он удобен.

    20.07.2011
  • Я бы вряд ли назвал это мьютексом, по крайней мере, в традиционном смысле, потому что у вас нет двух потоков, работающих в контексте одного блока в любое время. 20.07.2011
  • мьютекс - это просто алгоритм, который помогает «избежать одновременного использования общего ресурса». Хотя многопоточность создает потребность в мьютексах, в определении нет ничего, что говорило бы, что мьютекс специфичен для описываемой вами ситуации. 21.07.2011
  • Вы правы насчет формального определения мьютекса. Но вряд ли люди думают об этом, когда говорят о мьютексах в реальном мире. 21.07.2011
  • Это не работает должным образом. К сожалению, повторные щелчки по-прежнему вызывают вызов ajax. Есть еще идеи? 21.07.2017
  • Совершенно уверен, что это должно быть заключено в while с setTimeout или setInterval с clearInterval после n сбоев, чтобы у вас была логика повторных попыток и тайм-аута. Если оставить как есть, вы просто обойдете заблокированный код. Внешняя обработка мьютексов и общих объектов так же важна, как и сами реализации. 28.04.2019
  • Старый пост, но мне кажется, что если операция чтения if(!save_lock) и запись save_lock=true не являются одной атомарной операцией, то этот блок сможет запустить более одного потока. Нужна проверка и установка ИМХО. 23.09.2020
  • Прочитав еще немного, я думаю, что ошибался насчет атомарной операции. Из-за архитектуры js до завершения, AFAICT эти операции будут гарантированно выполняться вместе. По крайней мере, большую часть времени. 24.09.2020

  • 4

    Да, мьютексы могут потребоваться в Javascript при доступе к ресурсам, которые используются совместно вкладками / окнами, например localStorage.

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

    function appendToList(item) {
        var list = localStorage["myKey"];
        if (list) {
            list += "," + item;
        }
        else {
            list = item;
        }
        localStorage["myKey"] = list;
    }
    

    Между моментом, когда элемент localStorage был «получен» и «установлен», другая вкладка могла изменить значение. Как правило, это маловероятно, но возможно - вам нужно будет самостоятельно оценить вероятность и риск, связанный с любым разногласием в ваших конкретных обстоятельствах.

    См. Следующие статьи для получения более подробной информации:

    08.02.2018

    5

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

    Однако вам НЕОБХОДИМО беспокоиться о том, как ваш JavaScript будет обрабатывать несколько запросов ajax, возвращающихся не в том же порядке, в котором вы их отправляете. Итак, все, о чем вам действительно нужно беспокоиться, это убедиться, что ваши вызовы ajax обрабатываются таким образом, чтобы они не наступали друг другу на ноги, если результаты вернутся в другом порядке, чем вы их отправили.

    Это касается и таймаутов ...

    Когда JavaScript становится многопоточным, можно беспокоиться о мьютексах и тому подобном ...

    24.09.2008

    6

    JavaScript, язык, может быть сколь угодно многопоточным, но при встраивании движка javascript в браузер запускается только один обратный вызов (onload, onfocus, ‹script› и т. Д.) За раз (для каждого tab, предположительно). Предложение Уильяма об использовании Mutex для изменений между регистрацией и получением обратного вызова не следует воспринимать слишком буквально из-за этого, поскольку вы не захотите блокировать промежуточный обратный вызов, поскольку обратный вызов, который его разблокирует, будет заблокирован за текущим обратным вызовом ! (Вау, английский отстой, если говорить о потоковой передаче.) В этом случае вы, вероятно, захотите сделать что-то вроде повторной отправки текущего события, если установлен флаг, буквально или с помощью setTimeout ().

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

    Простите за стену текста!

    28.11.2008

    7

    События сигнализируются, но выполнение JavaScript по-прежнему однопоточное.

    Я понимаю, что при получении сигнала о событии движок останавливает то, что он выполняет в данный момент, чтобы запустить обработчик событий. После завершения обработчика выполнение скрипта возобновляется. Если обработчик событий изменил некоторые общие переменные, тогда возобновленный код увидит, что эти изменения появляются «неожиданно».

    Если вы хотите «защитить» общие данные, достаточно простого логического флага.

    24.09.2008
    Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]