pycurl/curl не соответствует параметру CURLOPT_TIMEOUT

У меня есть многопоточный скрипт, который иногда зависает при подключении к серверу, но сервер ничего не отправляет обратно. Netstat показывает подключенный сокет TCP. Это происходит, даже если у меня установлен TIMEOUT. Тайм-аут отлично работает в скрипте без потоков. Вот пример кода.

def xmlscraper(url):
  htmlpage = StringIO.StringIO()
  rheader = StringIO.StringIO()
  c = pycurl.Curl()
  c.setopt(pycurl.USERAGENT, "user agent string")
  c.setopt(pycurl.CONNECTTIMEOUT, 60)
  c.setopt(pycurl.TIMEOUT, 120)
  c.setopt(pycurl.FOLLOWLOCATION, 1)
  c.setopt(pycurl.WRITEFUNCTION, htmlpage.write)
  c.setopt(pycurl.HEADERFUNCTION, rheader.write)
  c.setopt(pycurl.HTTPHEADER, ['Expect:'])
  c.setopt(pycurl.NOSIGNAL, 1)
  c.setopt(pycurl.URL, url)
  c.setopt(pycurl.HTTPGET, 1)

pycurl.global_init(pycurl.GLOBAL_ALL)
for url in urllist:
    t = threading.Thread(target=xmlscraper, args=(url,))
    t.start()

Любая помощь будет принята с благодарностью! пытался решить это в течение нескольких недель.

изменить: URL-адрес имеет около 10 URL-адресов. Кажется, неважно, сколько их.

edit2: я только что проверил этот код ниже. Я использовал php-скрипт, который спит в течение 100 секунд.

import threading
import pycurl
def testf():
    c = pycurl.Curl()
    c.setopt(pycurl.CONNECTTIMEOUT, 3)
    c.setopt(pycurl.TIMEOUT, 6)
    c.setopt(pycurl.NOSIGNAL, 1)
    c.setopt(pycurl.URL, 'http://xxx.xxx.xxx.xxx/test.php')
    c.setopt(pycurl.HTTPGET, 1)
    c.perform()
t = threading.Thread(target=testf)
t.start()
t.join()

Pycurl в этом коде, кажется, правильно истекает. Я так понимаю, это как-то связано с количеством URL-адресов? ГИЛ?

редактировать3:

Я думаю, что это может быть связано с самой libcurl, потому что иногда, когда я проверяю скрипт, libcurl все еще подключен к серверу в течение нескольких часов подряд. Если бы время ожидания pycurl истекло, сокет был бы закрыт.


person Incognito    schedule 28.12.2010    source источник
comment
сколько URL-адресов находится в списке URL-адресов, когда возникает эта проблема? это все еще происходит только с одним (или несколькими) URL-адресами/потоками?   -  person Corey Goldberg    schedule 29.12.2010
comment
если вы запускаете несколько потоков, используя свой код «edit2», правильно ли они каждый тайм-аут?   -  person Corey Goldberg    schedule 29.12.2010
comment
да нормально работают. Попробовал это с парой сотен созданных потоков, и все время истекло должным образом.   -  person Incognito    schedule 29.12.2010


Ответы (2)


Я изменил ваш код «edit2», чтобы создать несколько потоков, и он отлично работает на моей машине (Ubuntu 10.10 с Python 2.6.6)

import threading
import pycurl

def testf():
    c = pycurl.Curl()
    c.setopt(pycurl.CONNECTTIMEOUT, 3)
    c.setopt(pycurl.TIMEOUT, 3)
    c.setopt(pycurl.NOSIGNAL, 1)
    c.setopt(pycurl.URL, 'http://localhost/cgi-bin/foo.py')
    c.setopt(pycurl.HTTPGET, 1)
    c.perform()

for i in range(100):
    t = threading.Thread(target=testf)
    t.start()

Я могу создать 100 потоков и все тайм-ауты в 3 секунды (как я указал).

Я бы пока не стал обвинять GIL и разногласия между потоками :)

person Corey Goldberg    schedule 28.12.2010

Потоки Python в некоторых ситуациях блокируются глобальной блокировкой интерпретатора («GIL»). Возможно, потоки, которые вы запускаете, не истекают по тайм-ауту, потому что на самом деле они запускаются недостаточно часто.

Этот связанный с StackOverflow вопрос может указать вам правильное направление:

person Brian Clapper    schedule 28.12.2010
comment
Насколько я понимаю, GIL влияет только на код Python. Я понял, что pycurl просто передает все в libcurl, и он сам обрабатывает тайм-аут. - person Incognito; 29.12.2010
comment
Однако GIL влияет на многопоточность Python. Проверьте соответствующий вопрос. - person Brian Clapper; 29.12.2010
comment
некоторым URL-адресам нужны файлы cookie, поэтому я не могу использовать cookielib. В противном случае я бы застрял с urllib2. - person Incognito; 29.12.2010
comment
Не могли бы вы уточнить, что потоки, которые вы запускаете, не истекают по тайм-ауту, потому что на самом деле они запускаются недостаточно часто? - person Incognito; 29.12.2010
comment
GIL не влияет на вызовы собственных библиотек, включая всю низкоуровневую сетевую блокировку, поскольку вызовы собственных библиотек освобождают GIL во время ожидания. (Некоторые глючные библиотеки не делают этого должным образом, например, я помню, что у PIL были проблемы с этим, но я ожидаю, что curl справится с этим.) - person Glenn Maynard; 29.12.2010
comment
Истинный. Но сами потоки создаются через Python. Отдельные потоки затем вызывают собственные библиотеки. Однако, сказав это (и нисколько не утруждая себя проверкой моего утверждения), я уступаю @Corey Goldberg, который проверил код под Python 2.6 и не обнаружил проблем с тайм-аутами. Итак, все, что я утверждаю, возможно, не имеет значения перед лицом фактических данных. ;-) - person Brian Clapper; 29.12.2010