2016-06-21 3 views
0

Я хочу отправлять запросы GET на сервер с фиксированными временными интервалами и регистрировать запрос и время отклика. Этот интервал может составлять порядка десятков миллисекунд. Мой первый подход состоял в том, чтобы использовать пул потоков, как описано в этом ответе https://stackoverflow.com/a/2635066/2390362. Затем я помещал задачу в очередь, когда истекает интервал времени, и пришло время сделать запрос. Хотя это сработало, оно, похоже, не слишком хорошо масштабируется.Измерение времени ответа с использованием Tornado AsyncHTTPClient

Я встретил Торнадо в этом другом ответе https://stackoverflow.com/a/25549675/2390362. Кажется, что это намного лучше с более тяжелыми нагрузками. Вот примерно, как я адаптировал его, чтобы сделать то, что я описал выше.

import time 
from tornado import ioloop, httpclient 
from datetime import datetime, timedelta 
from functools import partial 

i = 0 

def handle_request(req_time, log, response): 
    resp_time = datetime.now() 
    log.write("%s,\t%s,\t%s,\t%s\n"%(req_time.time(), resp_time.time(), (resp_time - req_time).total_seconds(), response.code)) 
    global i 
    i -= 1 
    if i == 0: 
     ioloop.IOLoop.instance().stop() 


def do_intervals(): 
    http_client = httpclient.AsyncHTTPClient() 
    req_count_limit = 3000 
    interval = 0.01 
    url = "http://www.someurl.com/" 
    global i 

    with open("log_file.log", 'a') as log: 

     for job_counter in range(req_count_limit): 

      i += 1 

      req_time = datetime.now() 
      current_callback = partial(handle_request, req_time, log) 
      http_client.fetch(url.strip(), current_callback, method='GET') 
      time.sleep(interval) 
     ioloop.IOLoop.instance().start() 


if __name__ == '__main__': 
    do_intervals() 

Однако, я заметил, что функция обратного вызова вызовов выполнять только после того, как все запросы были отправлены, а не тогда, когда приходит ответ. Это делает мое измерение времени ответа неточным. Я только что открыл Tornado и не совсем уверен, как работает код там. Есть ли способ получить время ответа, которое мне не хватает, или это единственный способ работы с торнадо и асинхронным HTTP?

ответ

0

В handle_request продолжительность запроса может быть разумно измерена с помощью resp_time - req_time.

Проблема в том, что вы блокируете цикл событий с помощью time.sleep, что означает, что большая часть обработки не прогрессирует до тех пор, пока не завершится цикл for. Смотрите Why isn’t this example with time.sleep() running in parallel? Попробуйте что-то вроде:

@gen.coroutine 
def do_intervals(): 
    # ... existing code ... 
    yield gen.sleep(interval) # instead of time.sleep 

IOLoop.instance().start() Удалить из do_intervals. Run это нравится:

IOLoop.instance().run_sync(do_intervals) 
+0

Так как 'выход gen.sleep (интервал)' брейки из цикла, я поставил часть внутри цикла в отдельной 'функции @ gen.coroutine' и используется' gen.sleep() '. Однако по-прежнему он вызывает вызов обработчика после отправки всех запросов. –

+0

Нет, вам действительно нужно «давать gen.sleep (interval)» во время итерации цикла, если вы хотите спать неблокирующим образом во время цикла. Если вы украшаете свои 'do_intervals'' gen.coroutine' и следуете остальным инструкциям, он будет работать так, как вы хотите. Я обновил свой ответ, чтобы быть более четким. –

+0

Я попытался использовать 'ioloop.PeriodicCallback', который работал, но ваше решение, похоже, улучшилось (мой пропустил некоторые обратные вызовы). PS: Мне также пришлось удалить 'ioloop.IOLoop.instance(). Stop()', иначе я бы получил 'TimeOutError' –

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