2014-09-01 4 views
0

Я учусь писать серверный сервер, который может обрабатывать тысячи подключений.Является ли торнадо веб-сервером async?

Я смотрю на примерный код, но нахожу, что он все еще записывает в логику синхронизации.

Например: (взять из http://www.tornadoweb.org/en/stable/gen.html)

@gen.coroutine 
def get(self): 
    http_client = AsyncHTTPClient() 
    response1, response2 = yield [http_client.fetch(url1), http_client.fetch(url2)] 
    print(response1.body, response2.body) 

Очевидно, что print оператор не может выполнить до получения ответа из двух выборок, иначе он будет бросать исключение из-за доступ не существует данные.

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

ответ

3

Да, tornado является асинхронным. Пример, который вы показываете, - coroutine; он фактически не блокирует и освобождает управление обратно к циклу событий торнадо при вызове yield. Control только возвращается к функции get, когда оба звонка http_client.fetch действительно завершены.

Эти два примера, на самом деле функционально эквивалентны в tornado:

class AsyncHandler(RequestHandler): 
    @asynchronous 
    def get(self): 
     http_client = AsyncHTTPClient() 
     http_client.fetch("http://example.com", 
          callback=self.on_fetch) 

    def on_fetch(self, response): 
     do_something_with_response(response) 
     self.render("template.html") 

И сопрограмма версия:

class GenAsyncHandler(RequestHandler): 
    @gen.coroutine 
    def get(self): 
     http_client = AsyncHTTPClient() 
     response = yield http_client.fetch("http://example.com") 
     do_something_with_response(response) 
     self.render("template.html") 

Сопрограммы позволяют писать асинхронный код, который выглядит синхронная, которая является более читаемым , Когда вышеуказанный код попадает в yield, get приостанавливает и возвращает объект Future, возвращенный http_client.fetch в декоратор gen.coroutine. У декоратора gen.coroutine есть волшебство в нем, которое назначает результат Future, возвращенный вызовом fetch, который должен быть возвращен обратно в get после его готовности.

+0

Я просто задаю вопрос типа Q & A ... Пожалуйста, взгляните на мой ответ. – Eugene

-1

Да!

Вполне вероятно, что с двумя разными шаблонами можно использовать yield и coroutine между длинными работами и медленными операциями ввода-вывода. Я только что совершил критическую ошибку.

  • В длительных работах

    1. next() способ его генератора неоднократно называли, и делать единицы работы каждый раз.
    2. Если у вас есть более одного coroutine, планировщик будет вызывать каждый метод next() один за другим, поэтому он разделяет процессорное время между заданиями. Таким образом, это сотрудничество между заданиями, поэтому называется coroutine.
  • В медленных операций ввода-вывода

    1. next() метод вызывается только один раз для каждой yield точки.
    2. После того, как yield с момента выполнения операции ввода-вывода, операция ввода-вывода имеет делегат ядра ОС. Планировщик добавит обратный вызов при завершении операции ввода-вывода, который вызовет метод next().
    3. И теперь вопрос для планировщика, когда следует позвонить методу next(). Это работает от асинхронной функции уровня ОС, например epoll, IOCP до планировщика уведомлений при завершении ввода-вывода.
    4. Таким образом, весь поток, работающий до точки ввода IO, чем yield, чтобы сдать выполнение. После завершения ввода-вывода он продолжит выполнение по вызову next() из планировщика.
    5. Последствия этого потока управления точно так же с обратного вызова шаблона, оба
      • бежать к точке донг IO
      • хэндовера Казнь поэтому процесс может выполнять другие работы
      • IO была завершена, по-прежнему работает ,
      • Единственное различие заключается в том, что один из них продолжает выполнять предыдущую функцию, а другой продолжает новую функцию обратного вызова.

Итак, в заключение:

  • в длительных заданий, планировщик будет вызывать каждый next() методу , когда процесс находится в режиме ожидания.

  • в медленных операций ввода-вывода, метод next() является вызывается только один раз, когда операции ввода-вывода завершена.

Я думаю, если вы понимаете, что вы поймете, что использование yield и coroutine на самом деле может иметь такую ​​же силу с callback.

+1

Из вступительного документа Tornado: «Tornado - это веб-инфраструктура Python и асинхронная сетевая библиотека». Хотя есть различия между асинхронными и неблокирующими, вы немного отсюда. –

+0

Торнадо является асинхронным и неблокирующим. На странице документа, на которой вы ссылались, описаны примеры кода торнадо, которые используют обратные вызовы и сопрограммы как асинхронные. Кроме того, кусок про легкие потоки, которые по-настоящему не делают асинхронными, - это ссылка на 'gevent', а не сопрограммы. – dano

+1

Разница между «блокировкой» и «асинхронным», как описано в документах торнадо, просто «возвращает ли этот код, прежде чем он действительно закончит выполнение своей работы?» Если это так, это асинхронно. Если он ждет завершения работы до возвращения, он блокирует. Tornado позволяет вам писать код в обоих этих стилях.Теперь торнадо также позволяет вам делать неблокирующие вызовы ввода/вывода в синхронных функциях через сопрограммы, но их можно легко использовать асинхронным способом (не уступая им). – dano

Смежные вопросы