Ответ 1
Примечание. Я использую Thin как синоним для всех веб-серверов, реализующих расширение async Rack (т.е. Rainbows!, Ebb, будущие версии Puma,...)
Q1. Правильно. Он завершит генерацию ответа (aka call
) в EventMachine.defer { ... }
, что приведет к тому, что EventMachine вытолкнет его в свой встроенный пул потоков.
Q2. Использование async.callback
в сочетании с EM.defer
на самом деле не имеет особого смысла, так как оно в основном будет использовать пул потоков, в результате получится аналогичная конструкция, как описано в Q1. Использование async.callback
имеет смысл, если использовать только библиотеки eventmachine для ввода-вывода. Тонкий будет отправлять ответ клиенту один раз, когда env['async.callback']
вызывается с нормальным ответом Rack в качестве аргумента.
Если тело является EM::Deferrable
, Thin не будет закрывать соединение до тех пор, пока это отложенное не удастся. Хорошо сохранившийся секрет: если вы хотите больше, чем просто длительный опрос (т.е. Сохранить соединение открытым после отправки частичного ответа), вы также можете вернуть объект EM::Deferrable
в качестве объекта тела без использования throw :async
или кода состояния -1
.
Q3. Вы догадываетесь правильно. Резьбовая подача может повысить нагрузку на неизмененное приложение Rack. Я вижу улучшение на 20% для простых приложений Sinatra на моей машине с Ruby 1.9.3, даже больше при работе на Rubinius или JRuby, где все ядра могут быть использованы. Второй подход полезен, если вы пишете свое приложение определенным образом.
Вы можете бросить много магии и хаков на вершине стойки, чтобы использовать не-событие приложение (см. em-synchrony или synatra-synchrony), но это оставит вас в отладке и зависимости ад.
Асинхронный подход имеет смысл с приложениями, которые, как правило, лучше всего решать с помощью управляемого события, например веб-чата. Однако я бы не рекомендовал использовать многопоточный подход для реализации длинного опроса, потому что каждое соединение для голосования блокирует поток. Это оставит вас либо тонны потоков, либо соединений, с которыми вы не можете справиться. По умолчанию пул потоков EM имеет размер 20 потоков, ограничивая до 20 ожидающих соединений для каждого процесса.
Вы можете использовать сервер, который создает новый поток для каждого входящего соединения, но создание потоков дорого (за исключением MacRuby, но я бы не использовал MacRuby в любом производственном приложении). Примеры serv и net-http-server. В идеале, вы хотите, это n: m сопоставление запросов и потоков. Но там нет сервера, предлагающего это.
Если вы хотите узнать больше на эту тему: я выступил с презентацией об этом в Rocky Mountain Ruby (и тонне других конференций). Видеозапись можно найти на ошибках.