Я могу найти много информации о том, как работает длинный опрос (например, это и это), но не могу найти просто примеров того, как реализовать это в коде.
Все, что я могу найти, это Cometd, который опирается на структуру Dojo JS и довольно сложную серверную систему.
В принципе, как мне использовать Apache для обслуживания запросов и как написать простой скрипт (скажем, на PHP), который будет «долго опрашивать» сервер на предмет новых сообщений?
Пример не обязательно должен быть масштабируемым, безопасным или полным, он просто должен работать!






Я использовал это, чтобы разобраться с Comet, я также настроил Comet с помощью сервера Java Glassfish и нашел множество других примеров, подписавшись на cometdaily.com
Я думаю, что клиент выглядит как обычный асинхронный запрос AJAX, но вы ожидаете, что на возврат потребуется «много времени».
Тогда сервер выглядит так.
while (!hasNewData())
usleep(50);
outputNewData();
Итак, запрос AJAX отправляется на сервер, вероятно, включая отметку времени последнего обновления, чтобы ваш hasNewData() знал, какие данные у вас уже есть.
Затем сервер находится в спящем цикле до тех пор, пока не станут доступны новые данные. Все это время ваш запрос AJAX все еще подключен, просто зависает в ожидании данных.
Наконец, когда доступны новые данные, сервер передает их вашему запросу AJAX и закрывает соединение.
Нет, усон - это не долгое ожидание. И весь смысл «ожидания» состоит в том, чтобы на время заблокировать ваш поток. Вероятно, он имел в виду 50 миллисекунд (usleep (50000)), а не 50 микросекунд! Но в любом случае, с типичной настройкой Apache / PHP, есть ли способ любой другой сделать это?
Ну, из принципа, вы не можете сделать функцию блокировки сообщений чата без ожидания.
Действительно здорово! Я создал рекурсивную функцию на сервере для проверки новых данных. Но какой продукт лучше всего подходит для эффективного использования длительного опроса? Я использую обычный Apache, и сервер не отвечает, когда я открываю более 4/5 вкладок браузера :( Ищу что-то для использования с PHP
Это проще, чем я изначально думал ... В основном у вас есть страница, которая ничего не делает, пока данные, которые вы хотите отправить, не будут доступны (скажем, не придет новое сообщение).
Вот действительно простой пример, который отправляет простую строку через 2-10 секунд. 1 из 3 шансов вернуть ошибку 404 (чтобы показать обработку ошибок в следующем примере Javascript)
msgsrv.php
<?php
if (rand(1,3) == 1){
/* Fake an error */
header("HTTP/1.0 404 Not Found");
die();
}
/* Send a string after a random number of seconds (2-10) */
sleep(rand(2,10));
echo("Hi! Have a random number: " . rand(1,10));
?>
Примечание. На реальном сайте запуск этого на обычном веб-сервере, таком как Apache, быстро свяжет все "рабочие потоки" и оставит его неспособным отвечать на другие запросы. Есть способы обойти это, но рекомендуется написать «сервер длительного опроса» в чем-то вроде Python скрученный, который не полагается на один поток на запрос. комета - популярный (который доступен на нескольких языках), а Торнадо - это новый фреймворк, созданный специально для таких задач (он был построен для кода длинного опроса FriendFeed) ... но, как простой пример, Apache более чем адекватен ! Этот сценарий можно легко написать на любом языке (я выбрал Apache / PHP, поскольку они очень распространены, и я запускал их локально)
Затем в Javascript вы запрашиваете указанный выше файл (msg_srv.php) и ждете ответа. Когда вы его получаете, вы действуете в соответствии с данными. Затем вы запрашиваете файл и снова ждете, действуете в соответствии с данными (и повторяете)
Ниже приводится пример такой страницы. Когда страница загружается, она отправляет начальный запрос файла msgsrv.php. Если это удается, мы добавляем сообщение в блок #messages, а затем через 1 секунду вызываем функцию waitForMsg. снова, что вызывает ожидание.
1-секундный setTimeout() - это действительно базовый ограничитель скорости, он отлично работает и без него, но если msgsrv.phpвсегда возвращается мгновенно (например, с синтаксической ошибкой) - вы наводняете браузер, и он может быстро зависнуть. Это было бы лучше сделать, проверив, содержит ли файл действительный ответ JSON, и / или сохранив текущее количество запросов в минуту / секунду с соответствующей паузой.
Если страница ошибается, он добавляет ошибку в div #messages, ждет 15 секунд, а затем пытается снова (аналогично тому, как мы ждем 1 секунду после каждого сообщения)
Этот подход хорош тем, что он очень устойчив. Если интернет-соединение клиента прерывается, оно истечет по таймауту, а затем попытается снова подключиться - это зависит от того, как долго работает опрос, не требуется сложной обработки ошибок.
Во всяком случае, код long_poller.htm, использующий фреймворк jQuery:
<html>
<head>
<title>BargePoller</title>
<script src = "http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type = "text/javascript" charset = "utf-8"></script>
<style type = "text/css" media = "screen">
body{ background:#000;color:#fff;font-size:.9em; }
.msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
.old{ background-color:#246499;}
.new{ background-color:#3B9957;}
.error{ background-color:#992E36;}
</style>
<script type = "text/javascript" charset = "utf-8">
function addmsg(type, msg){
/* Simple helper to add a div.
type is the name of a CSS class (old/new/error).
msg is the contents of the div */
$("#messages").append(
"<div class='msg "+ type +"'>"+ msg +"</div>"
);
}
function waitForMsg(){
/* This requests the url "msgsrv.php"
When it complete (or errors)*/
$.ajax({
type: "GET",
url: "msgsrv.php",
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
success: function(data){ /* called when request to barge.php completes */
addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
$(document).ready(function(){
waitForMsg(); /* Start the inital request */
});
</script>
</head>
<body>
<div id = "messages">
<div class = "msg old">
BargePoll message requester!
</div>
</div>
</body>
</html>
Не могли ли проскользнуть некоторые сообщения с использованием этой идеи? За этот 1-секундный тайм-аут, скажем, было отправлено 1000 сообщений чата, как сервер узнает, что нужно отправить 1000 сообщений именно этому клиенту?
Наверное. Это очень упрощенный пример, демонстрирующий концепцию. Чтобы сделать это лучше, вам понадобится более сложный серверный код, где он будет хранить эти 1000 сообщений для этого конкретного клиента и отправлять их одним блоком. Вы также можете безопасно уменьшить время ожидания waitForMsg
отличное решение. Работает прямо из коробки. Кажется, здесь я отвечу на мой вопрос: stackoverflow.com/questions/3002213/…. Прекрасная работа.
Разве этот пример не открывает новое соединение для каждого waitForMsg ()?
Это просто повторяющиеся AJAX-подключения к серверу с интервалом в 1 секунду. Это не имеет ничего общего с «долгим опросом». Длительный опрос должен поддерживать соединение, пока истекает время ожидания клиента.
@Delee, почему бы тебе просто не опубликовать свое решение?
@Delee Вы ошибаетесь. Тайм-аут в 1 секунду устанавливается только после успешного завершения запроса на длительный опрос, если запрос на длительный опрос не завершается, он истекает через 50 секунд.
вопрос в том, что делает настоящий PHP-скрипт вместо sleep(rand(2,10));? для того, чтобы ничего не делать, опрашивать базу данных каждые 100 миллисеков? когда он решает умереть?
Мне любопытно, может ли Apache Tomcat обрабатывать этот длинный опрос или, как Apache, он также связывает сервер с большим количеством запросов? Любые идеи по этому поводу.
@Bala без понятия, возможно, стоит отдельный вопрос, хотя эта ветка форума подразумевает, что у него есть ограничение на пул рабочих потоков
Ранее я применял аналогичную технику на своем форуме - js запрашивает файл php на сервере, который затем циклически проверяет наличие новых сообщений в течение максимум 30 секунд, а затем возвращает либо false, либо новые сообщения. Затем JS обрабатывает ответ и отправляет другой запрос. Он работает нормально, но, похоже, сильно замедляет работу браузера, когда я покидаю страницу, если был ожидающий запрос ... Почему это? На мой взгляд, браузер просто запросит следующую страницу, и PHP завершит работу и затем отправит свой ответ, но его никто не получит. Почему он замедляется? Как я мог это исправить?
Уловка, позволяющая избежать пропущенных сообщений, состоит в том, чтобы включить Id или TimeStamp последнего сообщения, полученного клиентом, в запрос AJAX - таким образом сервер может легко вернуть «все сообщения с [Blah]».
Итак, я предполагаю, что меня смущает, хотя в функции успеха и ошибки запрос ajax перезапускается, поэтому разве не создается новое http-соединение для каждого запроса ajax?
@Rooster Правильно, для каждого он создает отдельный HTTP-запрос. Это похоже на долгий опрос, а не на повторное использование одного соединения. Похоже, вы ищете что-то вроде многостраничной потоковой передачи HTTP, веб-сокетов и т. д.
Чем это так отличается от выполнения setInterval () каждые X секунд и загрузки данных таким образом? В любом случае тот или иной сценарий считывает и отправляет данные с сервера каждые X секунд.
@ Chud37 Аналогично, но с меньшей задержкой. Соединение с длительным опросом получает данные, как только они становятся доступными, тогда как при опросе setInterval каждые 5 секунд данные могут стать доступными через 1 секунду, но у вас есть 4-секундный промежуток, прежде чем они станут видимыми.
очень капот спасибо! это спасло мне день!
У меня есть очень простой пример чата как часть плевать.
Редактировать: (поскольку каждый вставляет сюда свой код)
Это полный многопользовательский чат на основе JSON с использованием длинного опроса и плевать. Это демонстрация того, как выполнять вызовы, поэтому, пожалуйста, не обращайте внимания на проблемы XSS. Никто не должен развертывать это без предварительной дезинфекции.
Обратите внимание на то, что клиент всегда имеет соединение с сервером, и как только кто-нибудь отправит сообщение, все сразу же увидят его.
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Copyright (c) 2008 Dustin Sallings <[email protected]> -->
<html lang = "en">
<head>
<title>slosh chat</title>
<script type = "text/javascript"
src = "http://code.jquery.com/jquery-latest.js"></script>
<link title = "Default" rel = "stylesheet" media = "screen" href = "style.css" />
</head>
<body>
<h1>Welcome to Slosh Chat</h1>
<div id = "messages">
<div>
<span class = "from">First!:</span>
<span class = "msg">Welcome to chat. Please don't hurt each other.</span>
</div>
</div>
<form method = "post" action = "#">
<div>Nick: <input id='from' type = "text" name = "from"/></div>
<div>Message:</div>
<div><textarea id='msg' name = "msg"></textarea></div>
<div><input type = "submit" value = "Say it" id = "submit"/></div>
</form>
<script type = "text/javascript">
function gotData(json, st) {
var msgs=$('#messages');
$.each(json.res, function(idx, p) {
var from = p.from[0]
var msg = p.msg[0]
msgs.append("<div><span class='from'>" + from + ":</span>" +
" <span class='msg'>" + msg + "</span></div>");
});
// The jQuery wrapped msgs above does not work here.
var msgs=document.getElementById("messages");
msgs.scrollTop = msgs.scrollHeight;
}
function getNewComments() {
$.getJSON('/topics/chat.json', gotData);
}
$(document).ready(function() {
$(document).ajaxStop(getNewComments);
$("form").submit(function() {
$.post('/topics/chat', $('form').serialize());
return false;
});
getNewComments();
});
</script>
</body>
</html>
Могу я узнать, как это всегда связано? Извините, если я спрашиваю что-то глупое, но я хочу это знать.
Он выполняет HTTP GET, и сервер блокирует GET до тех пор, пока не станут доступны данные. Когда данные поступают на сервер, сервер возвращает данные клиенту, ставит в очередь все, что может поступить, а затем клиент повторно подключается и забирает отсутствующие сообщения, если таковые имеются, в противном случае он снова блокируется.
Сначала это может быть неочевидно, но дело в том, что за `` всегда подключенное состояние '' отвечает ajaxStop с обратным вызовом getNewComments, поэтому он просто запускает его в конце каждого запроса ajax бесконечно
Спасибо за код, dbr. Просто небольшая опечатка в long_poller.htm вокруг линии
1000 /* ..after 1 seconds */
Я думаю так должно быть
"1000"); /* ..after 1 seconds */
чтобы он работал.
Для заинтересованных я попробовал эквивалент Django. Запустите новый проект Django, скажем lp для длительного опроса:
django-admin.py startproject lp
Вызовите приложение msgsrv для сервера сообщений:
python manage.py startapp msgsrv
Добавьте следующие строки в settings.py, чтобы иметь каталог шаблоны:
import os.path
PROJECT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = (
os.path.join(PROJECT_DIR, 'templates'),
)
Определите свои шаблоны URL в urls.py как таковые:
from django.views.generic.simple import direct_to_template
from lp.msgsrv.views import retmsg
urlpatterns = patterns('',
(r'^msgsrv\.php$', retmsg),
(r'^long_poller\.htm$', direct_to_template, {'template': 'long_poller.htm'}),
)
И msgsrv / views.py должно выглядеть так:
from random import randint
from time import sleep
from django.http import HttpResponse, HttpResponseNotFound
def retmsg(request):
if randint(1,3) == 1:
return HttpResponseNotFound('<h1>Page not found</h1>')
else:
sleep(randint(2,10))
return HttpResponse('Hi! Have a random number: %s' % str(randint(1,10)))
Наконец, шаблоны / long_poller.htm должны быть такими же, как указано выше, с исправленной опечаткой. Надеюсь это поможет.
Собственно, "15000" - это синтаксическая ошибка. setTimeout принимает целое число в качестве второго параметра.
Этот ответ требует доработки. Это кульминация одного или нескольких комментариев и отдельного ответа или ответов.
Это хороший 5-минутный скринкаст о том, как проводить длинный опрос с использованием PHP и jQuery: http://screenr.com/SNH
Код очень похож на приведенный выше пример dbr.
Я думаю, вы должны рассматривать это только как введение в длинный опрос, потому что эта реализация наверняка убьет ваш сервер с множеством одновременных пользователей.
Я только что узнал обо всем этом ... насколько это надежно или нет, это с несколькими пользователями ... скажем, 10 болтают назад и вперед?
Взгляните на это сообщение в блоге, в котором есть код для простого чат-приложения на Python / Django / Gevent.
Торнадо предназначен для длительного опроса и включает очень минимальный (несколько сотен строк Python) приложение для чата в / примеры / chatdemo, включая код сервера и код клиента JS. Это работает так:
Клиенты используют JS для запроса обновлений с (номер последнего сообщения), сервер URLHandler получает их и добавляет обратный вызов для ответа клиенту в очередь.
Когда сервер получает новое сообщение, срабатывает событие onmessage, проходит через обратные вызовы и отправляет сообщения.
Клиентский JS получает сообщение, добавляет его на страницу, а затем запрашивает обновления с этого нового идентификатора сообщения.
Группа WS-I опубликовала что-то под названием «Надежный безопасный профиль», в котором есть Glass Fish, и Реализация .NET, который, по-видимому, взаимодействовать хорошо.
Если повезет, есть и реализация Javascript.
Существует также реализация Silverlight, в которой используется HTTP-дуплекс.. Вы можете использовать объект подключить javascript к Silverlight для получения обратных вызовов при возникновении push.
Также есть коммерческие платные версии.
Ниже приведено решение для длинных опросов, которое я разработал для Inform8 Web. В основном вы переопределяете класс и реализуете метод loadData. Когда loadData возвращает значение или время ожидания операции истекает, он распечатывает результат и возвращается.
Если обработка вашего скрипта может занять больше 30 секунд, вам может потребоваться изменить вызов set_time_limit () на что-то более длительное.
Лицензия Apache 2.0. Последняя версия на github https://github.com/ryanhend/Inform8/blob/master/Inform8-web/src/config/lib/Inform8/longpoll/LongPoller.php
Райан
abstract class LongPoller {
protected $sleepTime = 5;
protected $timeoutTime = 30;
function __construct() {
}
function setTimeout($timeout) {
$this->timeoutTime = $timeout;
}
function setSleep($sleep) {
$this->sleepTime = $sleepTime;
}
public function run() {
$data = NULL;
$timeout = 0;
set_time_limit($this->timeoutTime + $this->sleepTime + 15);
//Query database for data
while($data == NULL && $timeout < $this->timeoutTime) {
$data = $this->loadData();
if ($data == NULL){
//No new orders, flush to notify php still alive
flush();
//Wait for new Messages
sleep($this->sleepTime);
$timeout += $this->sleepTime;
}else{
echo $data;
flush();
}
}
}
protected abstract function loadData();
}
Здесь - это классы, которые я использую для длительного опроса в C#. Всего существует 6 классов (см. Ниже).
Хорошо ... так ПОЧЕМУ это было отклонено? Эти классы действительно являются действительными примерами длительного опроса.
Настоящий длинный опрос - это не (просто) практика увеличения интервала, когда вы проводите обычный опрос (на ресурсе). Это часть более крупного паттерна ... который «в некоторой степени» подлежит интерпретации ... но только в определенных областях общей реализации. Тем не менее ... эти классы следуют указанному шаблону! Так что, если у вас есть причина проголосовать против этого ... Мне действительно была бы интересна причина.
Возможно, он был отклонен, поскольку он напрямую не решает вопрос о простом примере кода. Конечно, я не голосовал против, поэтому могу только догадываться.
Для реализации ASP.NET MVC посмотрите SignalR который доступен в NuGet .. обратите внимание, что NuGet часто устарел из Источник Git, который очень часто фиксируется.
Узнайте больше о SignalR на блог Скотта Хансельмана
Вот простой пример длинного опроса в PHP от Эрика Даббельбура, использующий заголовок Content-type: multipart/x-mixed-replace:
<?
header('Content-type: multipart/x-mixed-replace; boundary=endofsection');
// Keep in mind that the empty line is important to separate the headers
// from the content.
echo 'Content-type: text/plain
After 5 seconds this will go away and a cat will appear...
--endofsection
';
flush(); // Don't forget to flush the content to the browser.
sleep(5);
echo 'Content-type: image/jpg
';
$stream = fopen('cat.jpg', 'rb');
fpassthru($stream);
fclose($stream);
echo '
--endofsection
';
А вот и демонстрация:
Вы можете попробовать icomet (https://github.com/ideawu/icomet), сервер кометы C1000K C++, созданный с помощью libevent. icomet также предоставляет библиотеку JavaScript, ее легко использовать так же просто, как
var comet = new iComet({
sign_url: 'http://' + app_host + '/sign?obj=' + obj,
sub_url: 'http://' + icomet_host + '/sub',
callback: function(msg){
// on server push
alert(msg.content);
}
});
icomet поддерживает широкий спектр браузеров и ОС, включая Safari (iOS, Mac), IE (Windows), Firefox, Chrome и т. д.
Почему бы не рассмотреть веб-сокеты вместо длительного опроса? Они очень эффективны и просты в установке. Однако они поддерживаются только в современных браузерах. Вот краткая справка.
Я думаю, что как только веб-сокеты будут реализованы повсюду (вероятно, не на долгие годы), они станут стандартом для такого рода приложений. К сожалению, пока мы не можем полагаться на них в производственных приложениях.
@Richard Однако вы можете использовать что-то вроде Socket.IO, которое обеспечивает автоматические резервные транспорты, обеспечивая функциональность, подобную веб-сокету, вплоть до IE 6.
Это один из сценариев, для которого PHP - очень плохой выбор. Как упоминалось ранее, вы можете очень быстро связать всех своих рабочих Apache, сделав что-то подобное. PHP создан для запуска, выполнения и остановки. Он не предназначен для запуска, подождите ... выполните, остановитесь. Вы очень быстро перегрузите свой сервер и обнаружите, что у вас невероятные проблемы с масштабированием.
Тем не менее, вы все еще можете сделать это с помощью PHP и не убивать ваш сервер с помощью nginx HttpPushStreamModule: http://wiki.nginx.org/HttpPushStreamModule
Вы устанавливаете nginx перед Apache (или чем-то еще), и он позаботится о том, чтобы одновременные соединения оставались открытыми. Вы просто отвечаете полезной нагрузкой, отправляя данные на внутренний адрес, что можно было бы сделать с помощью фонового задания или просто отправлять сообщения людям, которые ждут, когда приходят новые запросы. Это не позволяет процессам PHP оставаться открытыми во время длительного опроса.
Это не эксклюзивно для PHP и может быть выполнено с помощью nginx с любым серверным языком. Нагрузка одновременных открытых подключений равна Node.js, поэтому самая большая привилегия заключается в том, что она избавляет вас от НУЖНОСТИ Node для чего-то вроде этого.
Вы видите, как много других людей упоминают другие языковые библиотеки для проведения длительного опроса, и это не без оснований. PHP, естественно, просто не подходит для такого типа поведения.
Это проблема Apache или PHP? Были бы у меня проблемы с долгим опросом, если бы мой PHP-код работал непосредственно на nginx или lighttpd?
Это не столько проблема PHP, сколько неправильное использование PHP. При каждом запросе PHP запускает сценарий с нуля, загружая библиотеки по мере необходимости, выполняя его код, а затем завершая работу, пока выполняется сборка мусора, все началось в запросе. За прошедшие годы в PHP было внесено множество модификаций, чтобы минимизировать влияние, такое как поздние статические привязки, отложенная загрузка, кеширование байт-кода в памяти для удаления дискового ввода-вывода и т. д. Проблема остается в том, что PHP предназначен для запуска и остановки так же быстро. насколько возможно. Языки, которые загружаются один раз / boot и открывают поток для запроса, гораздо лучше подходят для длительного опроса.
Но чтобы ответить на вопрос, да, вы столкнетесь с проблемой независимо от того, используете ли вы Apache или что-то еще. Так работает PHP. Я должен исправить это, чтобы сказать, что если вы собираетесь иметь известную максимальную нагрузку трафика, PHP будет в порядке. Я видел встроенные системы, использующие PHP, у которых нет проблем, потому что есть всего несколько соединений. Потенциально во внутренней сети компании это также может быть разрешено. Однако для общедоступных приложений вы полностью убьете свои серверы по мере роста трафика.
Простейший NodeJS
const http = require('http');
const server = http.createServer((req, res) => {
SomeVeryLongAction(res);
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
// the long running task - simplified to setTimeout here
// but can be async, wait from websocket service - whatever really
function SomeVeryLongAction(response) {
setTimeout(response.end, 10000);
}
Сценарий для производства в Express, например, вы получите response в промежуточном программном обеспечении. У вас есть то, что вам нужно сделать, вы можете выделить все методы с длинным опросом в Map или что-то в этом роде (что видно другим потокам) и вызвать <Response> response.end(), когда будете готовы. В длинных опрашиваемых соединениях нет ничего особенного. Отдых - это то, как вы обычно структурируете свое приложение.
Если вы не понимаете, что я имею в виду, говоря об ограничении, это должно дать вам представление
const http = require('http');
var responsesArray = [];
const server = http.createServer((req, res) => {
// not dealing with connection
// put it on stack (array in this case)
responsesArray.push(res);
// end this is where normal api flow ends
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
// and eventually when we are ready to resolve
// that if is there just to ensure you actually
// called endpoint before the timeout kicks in
function SomeVeryLongAction() {
if ( responsesArray.length ) {
let localResponse = responsesArray.shift();
localResponse.end();
}
}
// simulate some action out of endpoint flow
setTimeout(SomeVeryLongAction, 10000);
server.listen(8000);
Как видите, вы действительно можете реагировать на все связи, одно - делать все, что хотите. Для каждого запроса существует id, поэтому вы должны иметь возможность использовать карту и получать доступ к конкретным вызовам API.
Это занятое ожидание, которое блокирует ваш текущий поток. Это совсем не масштабируется.