Javascript и проблемы параллелизма?

Предположим, у меня есть простой код:

var counter = 0;
var sharedResource = [];//some shared resource

function incrementAndModify(){
   if(counter == 0) {
      sharedResource.push(Math.random());//very sensitive data
      counter++;
   }
}

function init(){
    incrementAndModify();
    doAjaxGetWithCallback(function(){incrementAndModify();});
    incrementAndModify();
}

Итак, вопрос: будет ли функция incrementAndModify() выполняться атомарно или нет? Я читал, что JS работает в одном потоке и не может быть проблем с параллелизмом. Но вопрос пока открыт (по крайней мере для меня).

Вместо:

doAjaxGetWithCallback(function(){incrementAndModify();});

Я мог бы написать что-то вроде:

doAjaxGetWithCallback(function(){
doSomeCrazyStuffThatDoesNotUseSharedResource();
incrementAndModify();
doSomeOtherCrazyStuffThatDoesNotUseSharedResource();
});

person hades    schedule 21.03.2012    source источник
comment
атомарно означает что? я думаю, что это будет вызвано три раза один за другим. Какой вопрос еще открыт?   -  person zod    schedule 21.03.2012
comment
У меня много мыслей, но не все из них верны.   -  person hades    schedule 21.03.2012


Ответы (3)


JavaScript в браузере является однопоточным (за исключением web-workers), поэтому вам не нужно беспокоиться о параллелизме. По сути, каждый блок кода является атомарным, независимо от его длины. Если incrementAndModify() выполняет какие-то очень ресурсоемкие операции, отнимающие много времени, и приходит ответ AJAX, обратный вызов не будет выполняться до тех пор, пока текущий incrementAndModify() не завершится и не освободит единственный поток.

Это также причина, по которой синхронные вызовы AJAX не рекомендуются: запрос AJAX может занять некоторое время, в течение которого никакой другой код не может быть выполнен (поток выполнения излишне занят). Это приводит к «зависанию» графического интерфейса, поскольку никакие другие пользовательские события не обрабатываются.

Смотрите также

Кстати это:

doAjaxGetWithCallback(function(){incrementAndModify();});

можно записать так:

doAjaxGetWithCallback(incrementAndModify);
person Tomasz Nurkiewicz    schedule 21.03.2012
comment
Я не думаю, что ваше утверждение, что вам не нужно беспокоиться о параллелизме, верно, даже если каждый блок кода является атомарным, чего я не знал. Проблемы параллелизма, безусловно, все еще могут возникать, когда у вас есть обратные вызовы (или обещания, или наблюдаемые), которые каким-то образом разделяют состояние. Даже если обратный вызов завершается полностью до того, как начнется следующий, вы должны сделать поправку на то, что не знаете порядок, в котором происходят эти обратные вызовы. Тривиально с одним обратным вызовом, но, очевидно, сложность может стать огромной с несколькими обратными вызовами. - person mike rodent; 24.06.2017

Не бойтесь, это сработает только один раз.

// sync example
var happened = false;

setTimeout(dontDoTwice, 0);
setTimeout(dontDoTwice, 0);
setTimeout(dontDoTwice, 0);

function dontDoTwice() {
  if (!happened) {
    alert("ALERT! ALERT! ALERT!");
    happened = true;
  }
}

Немного более сложный пример: http://jsfiddle.net/7BZ6H/1/

person Jamund Ferguson    schedule 21.03.2012
comment
и как бы вы синхронизировались в этом сумасшедшем коде, если бы у вас было МНОГО таймеров и один общий ресурс? - person hades; 21.03.2012
comment
Все они по-прежнему обращаются к одному и тому же i, вам нужно беспокоиться только о порядке их вызова. JS довольно прост, вы не можете и обычно не должны делать причудливые вещи, как вы делаете в многопоточных языках, чтобы справиться с этим. Чтобы сделать этот код синхронным, нужно вывести его из таймера. Я немного не уверен в проблеме, которую вы на самом деле пытаетесь решить, поэтому, возможно, более подробная информация поможет мне дать более полезный ответ. - person Jamund Ferguson; 22.03.2012
comment
Я не пытаюсь решить проблему, я пытаюсь предотвратить проблему;) - person hades; 27.03.2012
comment
О-о-о, вы беспокоитесь, что if(count==0) могут вызвать дважды. Ответ нет. Обратные вызовы будут позже. Я обновлю свой лучшим примером! - person Jamund Ferguson; 27.03.2012

Да, функция incrementAndModify() всегда будет работать атомарно. Это связано с Run-to-completion. Завершение функции javascript.

Дополнительную информацию см. в разделе Почему в javascript нет инструмента управления параллелизмом. Детали.

person Uzair Farooq    schedule 17.07.2015