2016-09-27 3 views
0

Я пытаюсь добавить задержку между запросами асинхронным способом. Когда я использую Tornado gen.sleep (x), моя функция (запуск) не выполняется. Если я удалю выход из yield gen.sleep (1.0), функция вызывается, но никакая задержка не добавляется. Как добавить задержку между запросами в моем цикле for? Мне нужно контролировать запрос в секунду для внешнего API. Если я использую time.sleep, ответ откладывается после завершения всех запросов. Попробовал добавить декоратор @ gen.engine для запуска функции и никаких результатов.Tornado gen.sleep add delay

Код:

import collections 
import tornado.httpclient 


class BacklogClient(object): 
    MAX_CONCURRENT_REQUESTS = 20 

    def __init__(self, ioloop): 
     self.ioloop = ioloop 
     self.client = tornado.httpclient.AsyncHTTPClient(max_clients=self.MAX_CONCURRENT_REQUESTS) 
     self.client.configure(None, defaults=dict(connect_timeout=20, request_timeout=30)) 
     self.backlog = collections.deque() 
     self.concurrent_requests = 0 

    def __get_callback(self, function): 
     def wrapped(*args, **kwargs): 
      self.concurrent_requests -= 1 
      self.try_run_request() 
      return function(*args, **kwargs) 

     return wrapped 

    def try_run_request(self): 
     while self.backlog and self.concurrent_requests < self.MAX_CONCURRENT_REQUESTS: 
      request, callback = self.backlog.popleft() 
      self.client.fetch(request, callback=callback) 
      self.concurrent_requests += 1 

    def fetch(self, request, callback=None): 
     wrapped = self.__get_callback(callback) 

     self.backlog.append((request, wrapped)) 
     self.try_run_request() 


import time 
from tornado import ioloop, httpclient, gen 


class TornadoBacklog: 
    def __init__(self): 

     self.queue = 0 
     self.debug = 1 
     self.toProcess = [ 
      'http://google.com', 
      'http://yahoo.com', 
      'http://nytimes.com', 
      'http://msn.com', 
      'http://cnn.com', 
      'http://twitter.com', 
      'http://facebook.com', 
     ] 


    def handle_request(self, response): 

     print response.code 
     if not self.backlog.backlog and self.backlog.concurrent_requests == 0: 
      ioloop.IOLoop.instance().stop() 


    def launch(self): 
     self.ioloop = ioloop.IOLoop.current() 
     self.backlog = BacklogClient(self.ioloop) 

     for item in self.toProcess: 
      yield gen.sleep(1.0) 
      print item 
      self.backlog.fetch(
       httpclient.HTTPRequest(
        item, 
        method='GET', 
        headers=None, 
       ), 
       self.handle_request 
      ) 

     self.ioloop.start() 



def main(): 
    start_time = time.time() 

    scraper = TornadoBacklog() 
    scraper.launch() 

    elapsed_time = time.time() - start_time 
    print('Process took %f seconds processed %d items.' % (elapsed_time, len(scraper.toProcess))) 


if __name__ == "__main__": 
    main() 

Ссылка: https://github.com/tornadoweb/tornado/issues/1400

ответ

1

Торнадо сопрограммы есть два компонента:

  1. Они содержат "выход" заявления
  2. Они украшены "gen.coroutine"

Используйте «сопрограмму» декоратор на вашей функции «запуска»:

@gen.coroutine 
def launch(self): 

Запуск сопрограмму Торнадо от начала до конца, как это:

tornado.ioloop.IOLoop.current().run_sync(launch) 

Удалить вызов «ioloop.start» от ваша функция «запуска»: цикл запускает функцию «запуска», а не наоборот.

+0

Привет, Джесси, большое спасибо, я также избавился от своей функции остановки в handle_request и все отлично работало. Есть ли способ определить, есть ли ожидающий запрос на клиенте? Прямо сейчас я добавил дополнительную задержку, когда раньше был self.ioloop.start(). – spicyramen

+1

Чтобы остановить цикл, как только все запросы будут завершены, следуйте примеру параллельного веб-паука в документах Tornado, он решает вашу конкретную проблему: http://www.tornadoweb.org/en/latest/guide/queues.html –

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