2015-03-13 14 views
6

Napisałem prosty skrypt, który używa wątków do pobierania danych z usługi.Wystąpił błąd wyjątku "Wyjątek w wątku Wątek-13 (najprawdopodobniej wywołany podczas zamykania interpretera)"

__author__ = 'Igor' 
import requests 
import time 
from multiprocessing.dummy import Pool as ThreadPool 

ip_list = [] 
good_ip_list = [] 
bad_ip_list = [] 
progress = 0 

with open('/tmp/ip.txt') as f: 
    ip_list = f.read().split() 

def process_request(ip): 
    global progress 
    progress += 1 
    if progress % 10000 == 0: 
     print 'Processed ip:', progress, '...' 
    r = requests.get('http://*****/?ip='+ip, timeout=None) 
    if r.status_code == 200: 
     good_ip_list.append(ip) 
    elif r.status_code == 400: 
     bad_ip_list.append(ip) 
    else: 
     print 'Unknown http code received, aborting' 
     exit(1) 

pool = ThreadPool(16) 
try: 
    pool.map(process_request, ip_list) 
except: 
    for name, ip_list in (('/tmp/out_good.txt', good_ip_list),  ('/tmp/out_bad.txt', bad_ip_list)): 
     with open(name, 'w') as f: 
      for ip in ip_list: 
       print>>f, ip 

Ale po niektóre wnioski przetwarzane (40k-50k) i otrzymują:

wyjątek w wątku Thread-7 (najprawdopodobniej podniesiony podczas interpretera shutdown): Traceback (najnowsza rozmowę ostatni): Process zakończony z kodem wyjścia 0

Próbowano zmienić ustawienia usługę:

 <timeout>999</timeout> 
     <connectionlimit>600</connectionlimit> 
     <httpthreads>32</httpthreads> 
     <workerthreads>128</workerthreads> 

ale nadal ten sam błąd. Czy ktoś może mi pomóc - co jest nie tak?

+0

'druku> > f, ip' to jest literówka? Czy jest coś jeszcze w tracebacku? –

+1

'progress + = 1' w języku z zmiennymi danymi i przy użyciu wielu wątków bez żadnej ochrony ... Przestałem patrzeć na ten punkt;) – iced

+1

@PatrickCollins jak zrozumiałem - problem w request.exceptions.ConnectionError raise, tried aby go złapać i kontynuować działanie pool.map, ale ten sam efekt: – Igor

Odpowiedz

4

Dziękuję wszystkim, którzy pomogli mi rozwiązać ten problem. Przepisał cały kod i teraz działa idealnie:

__author__ = 'kulakov' 
import requests 
import time 
from multiprocessing.dummy import Pool as ThreadPool 

ip_list = [] 
good_ip_list = [] 
bad_ip_list = [] 

with open('/tmp/ip.txt') as f: 
    ip_list = f.read().split() 

s = requests.Session() 
def process_request(ip): 
    r = s.get('http://*****/?ip='+ip, timeout=None) 
    if r.status_code == 200: 
     # good_ip_list.append(ip) 
     return (ip, True) 
    elif r.status_code == 400: 
     # bad_ip_list.append(ip) 
     return (ip, False) 
    else: 
     print 'Unknown http code received, aborting' 
     exit(1) 

pool = ThreadPool(16) 
for ip, isOk in pool.imap(process_request, ip_list): 
    if isOk: 
     good_ip_list.append(ip) 
    else: 
     bad_ip_list.append(ip) 
pool.close() 
pool.join() 

for name, ip_list in (('/tmp/out_good.txt', good_ip_list), ('/tmp/out_bad.txt', bad_ip_list)): 
    with open(name, 'w') as f: 
     for ip in ip_list: 
      print>>f, ip 

Niektóre nowe informacje przydatne:

1) To był naprawdę zły pomysł, aby zapisać dane w różnych wątków w funkcji process_request, teraz powraca oświadczenie (true \ false) i ip.

2) keep alive jest w pełni obsługiwana przez requests domyślnie, ale jeśli chcesz go używać, należy utworzyć instancję obiektu Session i zastosować get metodę do niego tylko:

s = requests.Session() 
r = s.get('http://*****/?ip='+ip, timeout=None) 
1

to:

good_ip_list = [] 
bad_ip_list = [] 

nie jest bezpiecznie mieszać z Pythona wieloprocesorowych. Prawidłowym podejściem jest zwrócenie krotki (lub czegoś) z każdego połączenia do process_request, a następnie połączenie ich wszystkich na końcu. Równoczesne modyfikowanie progress z wielu procesów nie jest bezpieczne. Nie jestem pewien, jaki jest twój błąd, ale założę się, że to jakiś problem z synchronizacją, który zabija Pythona jako całość.

Usuń stan udostępniony i spróbuj ponownie.

+1

Dzięki, @Patrick Collins Chyba masz rację z tą sugestią: „Założę się, że jest jakiś problem synchronizacji, który zabija Python jako całości” może Pan wyjaśnić nieco więcej, ten punkt: „Usuń stan współdzielony i spróbuj ponownie. " Jako dane wejściowe mam funkcję "process_request" i listę "ip_list". Więc jaki jest właściwy sposób mapowania tego 2 obiektów nie w cyklu (jak próbowałem z cyklu działało idealnie, ale bardzo wolno), ale w różnych wątkach. Dziękuję. – Igor

+1

@Igor wyciągnij odniesienia do 'good_ip_list, bad_ip_list' i' progress' wewnątrz 'process_request'. Nie modyfikuj niczego wewnątrz 'process_request' z wyjątkiem obiektów, które utworzyłeś wewnątrz' process_request'. Zamiast tego powinieneś zwrócić coś w rodzaju "true" lub "false" w zależności od tego, czy adres IP był dobry, czy nie. –

Powiązane problemy