2016-07-22 2 views
1

Я использую Tornado для отправки запросов в быстрой периодической последовательности (каждые 0,1 с или даже 0,01 с) на сервер. Для этого я использую AsyncHttpClient.fetch с обратным вызовом для обработки ответа. Вот очень простой код, чтобы показать, что я имею в виду:Зачем длительный HTTP-раунд-время останавливает мой Tornado AsyncHttpClient?

from functools import partial 
from tornado import gen, locks, httpclient 
from datetime import timedelta, datetime 

    # usually many of these running on the same thread, maybe requesting the same server 
@gen.coroutine 
def send_request(url, interval): 
    wakeup_condition = locks.Condition() 
    #using this to allow requests to send immediately 
    http_client = httpclient.AsyncHTTPClient(max_clients=1000) 

    for i in range(300): 
     req_time = datetime.now() 

     current_callback = partial(handle_response, req_time) 
     http_client.fetch(url, current_callback, method='GET') 
     yield wakeup_condition.wait(timeout=timedelta(seconds=interval)) 

def handle_response(req_time, response): 
    resp_time = datetime.now() 
    write_to_log(req_time, resp_time, resp_time - req_time) #opens the log and writes to it 

Когда я тестировал его на локальном сервере, она работает нормально, запросы были отправлены вовремя, время спускоподъемных операций явно минимален. Однако, когда я тестирую его на удаленном сервере с большим временем обратного хода (особенно для более высоких нагрузок запроса), время запроса прерывается несколькими секундами: период ожидания между каждым запросом становится намного большим, чем желаемый период.

Почему? Я думал, что асинхронный код не будет затронут временем округления, так как он не блокируется, ожидая ответа. Есть ли какое-нибудь известное решение?

+0

Как вы называете 'send_request'? И что делает 'current_callback'? Если вы вызываете 'send_request'" parallely "и' current_callback' занимает некоторое значительное время, тогда может случиться, что вы складываете много запросов (так как поездка туда и обратно занимает некоторое время), и когда они возвращаются, они обрабатываются один за другим, замедляя все (в том числе новое планирование запросов) из-за характера одиночного потока. Таким образом, время ожидания увеличивается. – freakish

+0

Так кажется, что это на самом деле ** ** из-за асинхронности (у вас не было бы этой проблемы с потоками). Единственное обходное решение, которое я вижу, это сделать период ожидания короче и ждать снова, если таймаут не достигнут. – freakish

+0

@ freakish, как это связано с асинксом?Я потратил довольно много времени, переходя от потоков к асинхронному, потому что потоки делали намного хуже при больших нагрузках и потребляли много памяти для загрузки. –

ответ

1

После некоторых мастерингов и tcpdumping я пришел к выводу, что две вещи действительно замедляли мою сопрограмму.

  1. Компьютер я бегу по-видимому, не будет кэширование DNS, который для AsyncHTTPClient, как представляется, блокировка: С помощью этих двух исправлен глохнет понизилось чрезвычайно резко и timeout в yield wakeup_condition.wait(timeout=timedelta(seconds=interval)) гораздо лучше, уважаемый сетевой вызов. Таким образом, каждый запрос отправки coroutine имеет дополнительное время, чтобы дождаться разрешения DNS. Торнадо документы говорят:

tornado.httpclient в блоках конфигурации по умолчанию на разрешение DNS , но не на другой доступ к сети (для смягчения такого использования ThreadedResolver или tornado.curl_httpclient с правильно сконфигурированной сборки libcurl) ,

... и в the AsynHTTPClient docs

Для выбора curl_httpclient, вызовите AsyncHTTPClient.configure при запуске:

AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")

я в конечном итоге реализации свою собственную нить, которая решает и однако кэширует DNS, и это разрешило проблему, отправив запрос непосредственно на IP-адрес.

  1. URL, который я использовал, был HTTPS, изменив на HTTP-url улучшенную производительность. Для моего случая использования это не всегда возможно, но хорошо иметь возможность локализовать часть выпуска
Смежные вопросы