2010-12-28 17 views
5

Mam skrypt wielowątkowy, który czasami zawiesza się, gdy łączy się z serwerem, ale serwer nie odsyła niczego. Netstat pokazuje podłączone gniazdo tcp. Zdarza się to, nawet jeśli ustawiono opcję TIMEOUT. Limit czasu działa dobrze w niehartowanym skrypcie. Oto przykładowy kod.pycurl/curl nie następuje po opcji CURLOPT_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() 

Każda pomoc będzie bardzo ceniona! próbowali rozwiązać ten problem już od kilku tygodni.

edytuj: Lista URL zawiera około 10 adresów URL. Nie ma znaczenia, ile tam jest.

edit2: Właśnie przetestowałem ten kod poniżej. Użyłem skryptu php, który śpi przez 100 sekund.

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 w tym kodzie wydaje się być ustawiony prawidłowo. Sądzę więc, że ma to coś wspólnego z liczbą adresów URL? GIL?

Edit3:

myślę, że może to mieć związek z libcurl sama spowodować czasami kiedy sprawdzić libcurl skrypt jest wciąż podłączony do serwera całymi godzinami. Jeśli pycurl został prawidłowo ustawiony na czas, to gniazdo byłoby zamknięte.

+0

ile adresów URL w urllist gdy występuje ten problem? czy nadal ma miejsce tylko z jednym (lub kilkoma) adresami URL/wątkami? –

+0

jeśli uruchomisz wiele wątków przy użyciu twojego kodu "edit2", czy każdy timeout jest prawidłowy? –

+0

Tak, działają dobrze. Wypróbowałem go z kilkoma setkami zarodków i wszystko skończyło się poprawnie. – Incognito

Odpowiedz

3

I zmodyfikowanej swoją „Edit2” kod na tarło wielu wątków i działa dobrze na moim komputerze (Ubuntu 10.10 z 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() 

Mogę odrodzić 100 wątków i wszystkie limity czasu na 3 sekundy (jak to określiłem).

nie pojadę jeszcze obwinianie Gil wątek rywalizacji :)

1

Wątki Pythona są hamowane, w niektórych sytuacjach, przez globalną blokadę interpretera ("GIL"). Możliwe, że wątki, które uruchamiasz, nie kończą się, ponieważ nie są wystarczająco często uruchamiane.

Ten related StackOverflow question może skierować Cię w dobrym kierunku:

+0

z tego, co rozumiem, że GIL wpływa tylko na kod Pythona. Zrozumiałem, że pycurl po prostu przekazuje wszystko do libcurl, a ono samo obsługuje limit czasu. – Incognito

+0

GIL wpływa jednak na wątki w Pythonie. Sprawdź powiązane pytanie. –

+0

niektóre adresy URL wymagają plików cookie, więc nie mogę używać cookielib. W przeciwnym razie utknąłbym przy pomocy urllib2. – Incognito

Powiązane problemy