Почему AsyncHTTPClient в Tornado не отправляет запрос сразу?

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

Собственно, я скачиваю статью, затем анализирую ее и скачиваю изображения с упоминанием в ней.

Что меня беспокоит, так это то, что, хотя в моем журнале я ясно вижу сообщение о том, что .fetch() на URL-адресе фотографии был выдан, фактический HTTP-запрос не делается, как показано в Wireshark.

Я пытался возиться с max_client_count и HTTP-клиентом Curl/Simple, но бахвиор всегда один и тот же - пока все статьи не будут загружены, запросы на фотографии фактически не отправляются. Как это изменить?

обновл. какой-то псевдокод

@VictorSergienko Я работаю в Linux, поэтому по умолчанию, я думаю, используется версия EPoll. Вся система слишком сложна, но она сводится к:

@gen.coroutine
def fetch_and_process(self, url, callback):
  body = yield self.async_client.fetch(url)
  res = yield callback(body)
  return res

@gen.coroutine
def process_articles(self,urls):
  wait_ids=[]
  for url in urls:
     #Enqueue but don't wait for one
     IOLoop.current().add_callback(self.fetch_and_process(url, self.process_article))
     wait_ids.append(yield gen.Callback(key=url))
  #wait for all tasks to finish
  yield wait_ids

@gen.coroutine
def process_article(self,body):
   photo_url=self.extract_photo_url_from_page(body)
   do_some_stuff()
   print('I gonna download that photo '+photo_url)
   yield self.download_photo(photo_url)

@gen.coroutine
def download_photo(self, photo_url):
  body = yield self.async_client.fetch(photo_url)
  with open(self.construct_filename(photo_url)) as f:
   f.write(body)

И когда он печатает Я собираюсь загрузить эту фотографию, никакого фактического запроса не делается! Вместо этого он продолжает загружать больше статей и ставить в очередь больше фотографий, пока все статьи не будут загружены, только ТОГДА все фотографии запрашиваются в большом количестве.


person Ojomio    schedule 14.12.2014    source источник
comment
Я пока не знаю ответа, но, возможно, если вы поделитесь небольшим примером кода, который воспроизводит проблему, я смогу помочь ее отладить.   -  person A. Jesse Jiryu Davis    schedule 14.12.2014
comment
Главный вопрос в том, на чем ioloop работает клиент. Фрагмент кода обязательно поможет.   -  person Victor Sergienko    schedule 14.12.2014
comment
@VictorSergienko, добавил пример   -  person Ojomio    schedule 14.12.2014


Ответы (1)


AsyncHTTPClient имеет очередь, которую вы сразу же заполняете в process_articles ("Поставить в очередь, но не ждать ее"). К моменту обработки первой статьи ее фотографии будут стоять в конце очереди после всех остальных статей.

Если бы вы использовали yield self.fetch_and_process вместо add_callback в process_articles, вы бы чередовали статьи и их фотографии, но вы могли бы загружать только одну вещь за раз. Чтобы сохранить баланс между статьями и фотографиями, одновременно загружая более одной вещи, рассмотрите возможность использования пакета toro для примитивов синхронизации. Пример в http://toro.readthedocs.org/en/stable/examples/web_spider_example.html аналогичен вашему варианту использования.

person Ben Darnell    schedule 15.12.2014
comment
Я более или менее предположил, что там была очередь... Могу ли я изменить какие-либо настройки, такие как ее длина? И я часто получаю тайм-ауты, такие как 40000 мс - означает ли это, что время начинает отсчитываться еще до того, как будет сделан фактический запрос? - person Ojomio; 16.12.2014
comment
Очередь не ограничена; вы можете изменить количество запросов в полете одновременно с аргументом ключевого слова max_clients для AsyncHTTPClient (либо конструктором, либо методом класса configure; прочитайте документы о магии в конструкторе AsyncHTTPClient). Время ожидания запроса включает время, проведенное в очереди. - person Ben Darnell; 16.12.2014
comment
Спасибо за toro, это определенно полезно. Однако я не чувствую, что могу контролировать время ожидания с помощью request_timeout или connection_timeout: например, я указываю 60 секунд в качестве задержки, но в какой-то момент я получаю сообщение типа Время ожидания запроса истекло после 30000 ..... Более того, иногда мне говорят о разрешении таймаута, который я понимаю, что означает, но понятия не имею, как настроить - person Ojomio; 16.12.2014
comment
Я также прикрепляю эту ветку GGroups от @Ben Darnell, так как она более подробно объясняет ту же проблему [groups.google.com/d/topic/python-tornado/qqF5JQdP6XU/ - person Ojomio; 04.02.2015