2016-09-27 8 views
0

リクエスト間に遅延を非同期的に追加しようとしています。 私はTornado gen.sleep(x)を使用すると、私の関数(起動)が実行されません。 から削除すると、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

こんにちはJesse、ありがとう、私もhandle_requestで私の停止機能を取り除いて、すべてうまくいきました。クライアントに保留中の要求があるかどうかを検出する方法はありますか?今、私はself.ioloop.start()が使用されていた場所で余分な遅延を追加しました。 – spicyramen

+1

すべてのリクエストが完了するとすぐにループを停止するには、Tornadoのドキュメントにある同時ウェブスパイダーの例に従います。これは、あなたの正確な問題を解決しています。http://www.tornadoweb.org/en/latest/guide/queues.html –