2013-06-25 2 views
1

У меня есть менеджер API, который подключается к URL-адресу и захватывает некоторые json. Очень просто. Вырезать из метода:urlopen зависает в случайном порядке, timout игнорируется

req = Request(url) 
socket.setdefaulttimeout(timeout) 
resp = urlopen(req, None, timeout) 
data = resp.read() 
resp.close() 

Это отлично работает большую часть времени, но через случайные промежутки времени она занимает 5 секунд, чтобы выполнить запрос. Даже когда таймаут установлен на 0,5 или 1,0 или что-то еще. Я зарегистрировал его очень близко, поэтому я на 100% уверен, что строка, которая занимает время, занимает номер # 3 (т.е. resp = urlopen (req, None, timeout)).

Ive пытался все решения Ive найденные по теме тайм-аута декораторов и таймерами и т.д. (Для того, чтобы перечислить некоторые из них: Python urllib2.urlopen freezes script infinitely even though timeout is set, How can I force urllib2 to time out?, Timing out urllib2 urlopen operation in Python 2.4, Timeout function if it takes too long to finish )

Но ничего работает. Мое впечатление, что нить зависает, а urlopen что-то делает, и когда это делается, он размораживается, а затем все таймеры и таймауты возвращают ошибки таймаута. но время выполнения еще больше 5 секунд.

Я нашел this старый список рассылки относительно urllib2 и обработки закодированного кодирования. Поэтому, если проблема все еще присутствует, то решением может быть написать пользовательский urlopen на основе httplib.HTTP, а не httplib.HTTPConnection. Другим возможным решением является попытка использования многопоточной магии.

Оба решения кажутся агрессивными. И мне кажется, что тайм-аут не работает полностью.

Очень важно, чтобы время выполнения сценария не превышало 0,5 с. Кто знает, почему я испытываю зависания или, может быть, способ помочь мне?

Обновление, основано на принятом ответе: Я изменил подход и вместо этого использовал curl. Together w unix timeout работает так, как я хочу. Пример следующий код:

t_timeout = str(API_TIMEOUT_TIME) 
c_timeout = str(CURL_TIMEOUT_TIME) 
cmd = ['timeout', t_timeout, 'curl', '--max-time', c_timeout, url] 
prc = Popen(cmd, stdout=PIPE, stderr=PIPE) 
response = prc.communicate() 

Поскольку curl принимает только int как таймаут, я добавил таймаут. таймаут принимает поплавки.

ответ

1

Просматривая исходный код, значение timeout на самом деле является максимальным количеством времени, которое Python будет ожидать между получением пакетов с удаленного хоста.

Таким образом, если вы установите тайм-аут на две секунды, а удаленный хост отправит 60 пакетов со скоростью одного пакета в секунду, тайм-аут никогда не произойдет, хотя общий процесс все равно займет 60 секунд.

Поскольку функция urlopen() не возвращается, пока удаленный хост не завершит отправку всех HTTP-заголовков, то, если он отправляет заголовки очень медленно, вы не можете с этим поделать.

Если вам нужен общий срок, вам, вероятно, придется реализовать собственный HTTP-клиент с неблокирующими ввода-выводами.

+0

Отличный ответ. Спасибо. Даже если я чувствую, что должен быть общий тайм-аут. Ill update, если я реализую пользовательский HTTP-клиент, как было предложено. – user2520443