Я хочу отправлять запросы 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?
Так как 'выход gen.sleep (интервал)' брейки из цикла, я поставил часть внутри цикла в отдельной 'функции @ gen.coroutine' и используется' gen.sleep() '. Однако по-прежнему он вызывает вызов обработчика после отправки всех запросов. –
Нет, вам действительно нужно «давать gen.sleep (interval)» во время итерации цикла, если вы хотите спать неблокирующим образом во время цикла. Если вы украшаете свои 'do_intervals'' gen.coroutine' и следуете остальным инструкциям, он будет работать так, как вы хотите. Я обновил свой ответ, чтобы быть более четким. –
Я попытался использовать 'ioloop.PeriodicCallback', который работал, но ваше решение, похоже, улучшилось (мой пропустил некоторые обратные вызовы). PS: Мне также пришлось удалить 'ioloop.IOLoop.instance(). Stop()', иначе я бы получил 'TimeOutError' –