Чи потрібні Mutexes у JavaScript?


104

Я бачив це посилання: Реалізація взаємного виключення в JavaScript . З іншого боку, я прочитав, що в JavaScript немає ниток, але що це означає?

Коли відбуваються події, де в коді вони можуть перерватися?

І якщо в JS немає ниток, чи потрібно використовувати мютекси в JS чи ні?

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


1
Ні, ні мутекс чи будь-який інший інструмент контролю сумісності в JavaScript. Дивіться, чому в JavaScript не існує інструменту контролю сумісності .
Узаїр Фарук

Відповіді:


101

Javascript визначається як мова- реєрант, що означає, що користувачам не піддаються потоки потоків, в реалізації можуть бути потоки. Такі функції, як setTimeout()асинхронні зворотні дзвінки, повинні зачекати, поки движок сценарію вимкне, перш ніж вони зможуть запуститися.

Це означає, що все, що відбувається у події, має бути закінчено до того, як буде оброблено наступну подію.

З цього приводу, вам може знадобитися mutex, якщо ваш код робить щось там, де він очікує, що значення не зміниться між тим, коли асинхронна подія була запущена, і коли викликався зворотний виклик.

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

У той час як ви можете створити такий стан перегонів, як уникнути цього у вашому коді дуже просто, оскільки кожна функція буде атомною. Було б багато роботи і прийняти кілька дивних моделей кодування, щоб створити стан гонки насправді.


13
Зовсім не важко створити цю умову гонки: наприклад, у мене є подія "onkeyup" у полі, яка запускає виклик Ajax до БД, щоб отримати деякі значення. Швидке введення даних може легко призвести до результатів поза замовленням.
Thomasb

19

Відповіді на це питання трохи застаріли, хоча й правильні на той момент, коли вони були надані. І все-таки правильно, якщо дивитися на програму javascript на стороні клієнта, яка НЕ ​​використовує веб-працівників.

Статті про веб-робітників:
багатопоточна редакція в JavaScript за допомогою веб-робочих Mozilla для веб-робочих

Це наочно показує, що javascript через веб-працівників має багатопотокові можливості. Що стосується питання, чи потрібні мутекси в JavaScript? Я не впевнений у цьому. Але ця публікація stackoverflow видається актуальною:
Взаємне виключення для N Asynchronous Threads


3
вибух з минулого, але я зіткнувся з потребою в мютексах, коли кілька вкладок отримують доступ до одного локального сховища
psp

3
WebWorkers не впливають на повторне вступництво, оскільки вони не мають змінних станів і спілкуються з основною темою, передаючи повідомлення, які викликають події.
Альнітак

9

Як вказує @william,

вам може знадобитися mutex, якщо ваш код робить щось там, де він очікує, що значення не зміниться між тим, коли асинхронна подія була запущена, і коли викликався зворотний виклик.

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

Простий приклад - там, де у вас є кнопка, яка запускає виклик 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, але наскільки я знаю, що це проста мутекс, і це зручно.


4
Я навряд чи назвав би це мютекс, принаймні, не в традиційному розумінні, тому що у вас немає жодної нитки, що працює в контексті одного блоку в будь-який час.
Овеш

10
mutex - це просто алгоритм, який допомагає "уникнути одночасного використання загального ресурсу". Незважаючи на те, що багатопотоковість створює потребу в текстових текстах, у визначенні немає нічого, що говорить, що мутекс не є специфічним для описаної вами ситуації.
alzclarke

1
Ви вірно ставитесь до формального визначення мютексу. Але про це навряд чи люди думають, коли говорять про мютекси в реальному світі.
Овеш

Це працює не так, як очікувалося. На жаль, неодноразові клацання все ще запустить дзвінок Ajax. Будь-яка інша ідея?
Мохаммед Шаріф C

1
Досить впевнений, що це повинно бути завершено в whileз setTimeoutабо setIntervalз clearIntervalпісля п відмов, щоб у вас була логіка повтору та тайм-аута. Залишити "є" - це означає, що ви просто обійшли код, який заблокований. Зовнішнє поводження з мутексами та спільними об'єктами так само важливо, як і самі реалізації.
MrMesees

6

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

Однак одне, про що ви дійсно повинні турбуватися, - це те, як ваш JavaScript буде обробляти декілька запитів ajax, повертаючись у тому ж порядку, коли ви їх надсилали. Отже, все, про що потрібно насправді переживати, - це переконатися, що ваші дзвінки ajax обробляються таким чином, що вони не наступатимуть на ноги інших, якщо результати повернуться в іншому порядку, ніж ви їх надіслали.

Це стосується і тайм-аутів ...

Коли JavaScript зростає багатопоточністю, то, можливо, хвилюйтеся про мютекси тощо.


4

Так, мутакси можуть бути потрібні в Javascript при доступі до ресурсів, які спільно використовуються між вкладками / вікнами, як-от localStorage .

Наприклад, якщо у користувача відкриті дві вкладки, простий код на зразок наступного небезпечний:

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

Між часом, коли елемент localStorage "отримано" і "встановлено", інша вкладка могла змінити значення. Це взагалі малоймовірно, але можливо - вам потрібно буде судити про ймовірність та ризик, пов'язаний із будь-якими суперечками у ваших конкретних обставинах.

Детальніше див. У наступних статтях:


2

JavaScript, мова , може бути настільки багатопоточним, як ви хочете, але вбудовування браузера механізму javascript виконує лише один зворотний виклик (onload, onfocus, <script> і т.д. ...) одночасно (на вкладці, імовірно). Пропозиція Вільяма щодо використання Mutex для змін між реєстрацією та отриманням зворотного дзвінка не повинна сприйматись занадто буквально через це, оскільки ви не хочете блокувати вкладений зворотний виклик, оскільки зворотний виклик, який розблокує його, буде заблокований позаду поточного зворотного виклику. ! (Нічого так, англійська смокче говорити про нарізування різьби.) У цьому випадку, ймовірно, ви хочете зробити щось за принципом повторного відстеження поточної події, якщо встановлено прапор, або в прямому значенні, або з уподобанням setTimeout ().

Якщо ви використовуєте інше вбудовування JS і виконує декілька потоків одночасно, це може отримати трохи більше зубців, але завдяки способу JS може так легко використовувати зворотні виклики та блокує об'єкти в явному блокуванні доступу до власності - це не так вже й потрібно . Однак я був би здивований, якби вбудовування, розроблене для загального коду (наприклад, сценаріїв ігор), що використовувало багатоточну нитку, також не дало явних примітивів блокування.

Вибачте за стіну тексту!


0

Події сигналізуються, але виконання JavaScript все ще є однопоточним.

Я розумію, що коли сигналізується про подію, двигун зупиняє те, що виконується в даний момент, щоб запустити обробник подій. Після закінчення обробника виконання сценарію відновлюється. Якщо обробник подій змінив деякі загальні змінні, то відновлений код побачить, що ці зміни з'являться "не в синьому".

Якщо ви хочете "захистити" спільні дані, достатньо простого булевого прапора.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.