Нужны ли мьютексы в JavaScript? - PullRequest
       34

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

97 голосов
/ 24 сентября 2008

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

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

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

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

Ответы [ 7 ]

94 голосов
/ 24 сентября 2008

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

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

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

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

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

18 голосов
/ 22 февраля 2011

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

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

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

8 голосов
/ 20 июля 2011

Как указывает @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, но насколько я знаю, это простой мьютекс и он удобен.

5 голосов
/ 24 сентября 2008

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

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

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

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

2 голосов
/ 08 февраля 2018

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

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

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

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

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

1 голос
/ 28 ноября 2008

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

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

Извините за стену текста!

1 голос
/ 24 сентября 2008

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

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

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

...