Подтвердить что ты не робот

Асинхронный вызов всегда создает/вызывает новый поток?

Асинхронный вызов всегда создает новый поток?

Пример:

Если JavaScript однопоточный, то как он может выполнить обратную передачу async? Действительно ли он блокируется, пока не получит обратный вызов? Если да, действительно ли это асинхронный вызов?

4b9b3361

Ответ 1

Это интересный вопрос.

Асинхронное программирование - это парадигма программирования, которая в основном однопоточная, т.е. "после одного потока непрерывного выполнения".

Вы ссылаетесь на javascript, поэтому давайте обсудим этот язык в среде веб-браузера. Веб-браузер запускает один поток выполнения javascript в каждом окне, обрабатывает события (например, onclick = "someFunction()" ) и сетевые соединения (например, вызовы xmlhttprequest).

<script>
function performRequest() {
  xmlhttp.open("GET", "someurl", true);
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
      alert(xmlhttp.responseText);
    }
  }
  xmlhttp.send(sometext);
}
</script>
<span onclick="performRequest()">perform request</span>

(Это нерабочий пример, только для демонстрации понятий).

Чтобы сделать все в асинхронном режиме, управляющий поток имеет так называемый "основной цикл". Основной цикл выглядит примерно так:

while (true) {
    event = nextEvent(all_event_sources);
    handler = findEventHandler(event);
    handler(event);
}

Важно отметить, что это не "цикл занятости". Это похоже на спящую нить, ожидающую активности. Активность может быть введена пользователем (Движение мыши, нажатие кнопки, Ввод), или это может быть сетевая активность (ответ от сервера).

Итак, в приведенном выше примере

  • Когда пользователь нажимает на span, событие ButtonClicked будет сгенерировано, findEventHandler() найдет событие onclick в теге span, а затем этот обработчик будет вызван с событием.
  • Когда запрос xmlhttp создается, он добавляется в список источников событий all_event_sources.
  • После возвращения функции executeRequest() mainloop ждет следующего шага nextEvent(), ожидающего ответа. На этом этапе ничего не блокируется дальнейшими событиями.
  • Данные возвращаются с удаленного сервера, nextEvent() возвращает сетевое событие, обработчик события является методом onreadystatechange(), этот метод вызывается и запускается диалог alert().

Стоит отметить, что alert() - это диалоговое окно блокировки. Пока этот диалог завершен, дальнейшие события не могут быть обработаны. Это эксцентриситет javascript-модели веб-страниц, у нас есть легкодоступный метод, который блокирует дальнейшее выполнение в контексте этой страницы.

Ответ 2

Модель Javascript является однопоточной. Асинхронный вызов не является новым потоком, а скорее прерывает существующий поток. Он аналогичен прерываниям в ядре.

Да, имеет смысл иметь асинхронные вызовы с одним потоком. Здесь, как думать об этом: когда вы вызываете функцию в пределах одного потока, состояние для текущего метода переносится в стек (то есть локальные переменные). Подпрограмма вызывается и, в конце концов, возвращается, и в это время исходное состояние удаляется из стека.

При асинхронном обратном вызове происходит то же самое! Разница в том, что подпрограмма вызывается системой, а не текущим кодом, вызывающим подпрограмму.

Ответ 3

Несколько примечаний о JavaScript в частности:

XMLHttpRequest по умолчанию не блокируются. Метод send() возвращает сразу после того, как запрос был ретранслирован в базовый сетевой стек. Ответ от сервера будет планировать вызов вашего обратного вызова в цикле событий, как обсуждалось другими отличными ответами.

Для этого не требуется новый поток. Основной API сокетов можно выбрать, аналогично java.nio.channels в Java.

Можно построить синхронные объекты XMLHttpRequest, передав false в качестве третьего параметра open(). Это приведет к тому, что метод send() блокируется до тех пор, пока от сервера не будет получен ответ, таким образом, помещая цикл событий в зависимость от задержки сети и потенциально зависающего браузера до таймаута сети. Это Bad Thing ™.

Firefox 3.5 представит многопоточный JavaScript с честью к богу с классом Worker. Фоновый код выполняется в полностью отдельной среде и взаимодействует с окном браузера, планируя обратные вызовы в цикле событий.

Ответ 4

Во многих приложениях с графическим интерфейсом асинхронный вызов (например, Java invokeLater) просто добавляет объект Runnable в очередь очереди потоков GUI. Поток GUI уже создан, и он не создает новый поток. Но нити не требуются даже для асинхронной системы. Возьмем, к примеру, libevent, который использует select/poll/kqueue и т.д., Чтобы делать неблокирующие вызовы сокетам, что затем вызывает обратные вызовы для вашего кода, полностью без потоков.

Ответ 5

Нет, но будет задействовано более одного потока.

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

Если вы хотите выполнить синхронный вызов в этом контексте, вам нужно будет отправить сообщение и активно дожидаться, пока произойдет обратный вызов.

Итак, вкратце: задействовано более одного потока, но это не обязательно создает новый поток.

Ответ 6

Я не знаю о javascript, но, например, в мире Windows Forms, асинхронные вызовы могут выполняться без нескольких потоков. Это связано с тем, как работает Windows Message Pump. В основном приложение Windows Forms настраивает очередь сообщений, через которые Windows помещает сообщения, уведомляющие о событиях. Например, если вы переместите мышь, сообщения будут помещены в эту очередь. Приложение Windows Forms будет находиться в бесконечном цикле, в котором будут использоваться все сообщения, которые его выбрасывают. В соответствии с тем, что содержит каждое сообщение, он перемещает окна вокруг, перерисовывает их или даже вызывает пользовательские методы, среди прочего. Вызовы методов определяются делегатами. Когда приложение находит экземпляр делегата в очереди, он с радостью вызывает метод, переданный делегатом.

Итак, если вы используете метод, который делает что-то и хотите создать некоторую асинхронную работу без создания нового потока, все, что вам нужно сделать, это разместить экземпляр делегата в очередь с помощью метода Control.BeginInvoke. Теперь это не многопоточность, но если вы бросите в очередь очень маленькие куски работы, это будет выглядеть многопоточно. Если, с другой стороны, вы даете ему много времени для выполнения, приложение замерзает до тех пор, пока метод не будет выполнен, что будет выглядеть как замятое приложение, даже если оно что-то делает.