2013-07-30 8 views
5

Ich habe eine Anwendung, die eine Reihe von Servern alle paar Minuten abfragt. Um dies zu tun, laicht es ein Thread pro Server abzufragen (15 Server) und schreibt die Daten in ein Objekt zurück:Ausgabe Grund für Python Absturz

import requests 

class ServerResults(object): 
    def __init__(self): 
     self.results = [] 

    def add_server(some_argument): 
     self.results.append(some_argument) 

servers = ['1.1.1.1', '1.1.1.2'] 
results = ServerResults() 

for s in servers: 
    t = CallThreads(poll_server, s, results) 
    t.daemon = True 
    t.start() 

def poll_server(server, results): 
    response = requests.get(server, timeout=10) 
    results.add_server(response.status_code); 

Die CallThreads Klasse ist eine Hilfsfunktion, eine Funktion (in diesem Fall poll_server() mit Argumenten nennen (in diesem Fall s und results), können Sie die Quelle bei meinem Github Repo von Python utility functions sehen.Der Großteil der Zeit funktioniert das gut, aber manchmal ein Thread intermittierend hängt.Ich bin mir nicht sicher, warum, da ich a . Timeout auf der Anforderung GET In jedem Fall, wenn der Faden aufbauen hängt dann die aufgehängten Fäden im Laufe von Stunden oder Tagen, und dann stürzt Python:

File "/usr/lib/python2.7/threading.py", line 495, in start 
    _start_new_thread(self.__bootstrap,()) 
thread.error: can't start new thread 

Exception in thread Thread-575 (most likely raised during interpreter shutdown) 
Exception in thread Thread-1671 (most likely raised during interpreter shutdown) 
Exception in thread Thread-831 (most likely raised during interpreter shutdown) 

Wie könnte ich damit umgehen? Es scheint killablockingthreadinPython keine Möglichkeit zu sein. Diese Anwendung muss auf einem Raspberry Pi laufen, so dass große Bibliotheken wie twisted nicht passen, in der Tat muss ich die requests Bibliothek auch loswerden!

+0

Erstens, ist dies auf einem Pi, wenn es hängt, oder testen Sie woanders? Möglicherweise gibt es plattformspezifische Tools, mit denen Sie sehen können, was der Thread tut, aber Sie haben Ihre Plattform nicht angegeben. – Useless

+0

Zweitens, was ist "Anfragen"?Ohne das zu sehen, ist es unmöglich zu sagen, ob es dort eine Race Condition gibt – Useless

+0

Drittens, auch wenn Sie nicht verdreht verwenden, ist synchrone blockierungsfreie I/O in einem einzigen Thread viel besser skalierbar als diese – Useless

Antwort

4

Soweit ich das beurteilen kann, ein möglich Szenario ist, dass, wenn ein Faden „hängt“ für einen Server gegeben, es gibt „für immer“ bleiben wird. Das nächste Mal, wenn Sie Ihre Server abfragen, wird ein weiterer Thread erzeugt (_start_new_thread), bis zu dem Punkt, an dem Python abstürzt.

wahrscheinlich nicht die (Haupt-) Problem, aber Sie soll:

  • einen Thread-Pool verwenden - dies wird nicht die begrenzte Ressourcen des Systems betonen, so viel wie Laichen neue Fäden immer wieder .
  • Kontrolle, dass Sie ein „thread-kompatibel“ Mechanismus verwenden, um den gleichzeitigen Zugriff auf results zu behandeln. Vielleicht sperren ein semaphore oder mutex- Atom Teile des Codes. Wahrscheinlich wäre eine dedizierte Datenstruktur wie eine queue besser.

bezüglich des "hängen" per se - aufgepasst, dass das Timeout Arguments während "eine URL zu öffnen" (urlopen) mit dem Timeout Zusammenhang für den Verbindungsaufbau. Nicht für die tatsächliche Herunterladen von Daten:

Der optionale Parameter timeout ein Timeout in Sekunden für Blockierung Operationen wie der Verbindungsversuch gibt (wenn nicht anders angegeben, die globalen Standard-Timeout-Einstellung verwendet werden). Dies funktioniert nur für HTTP, HTTPS und FTP-Verbindungen.

+0

Danke. Eigentlich bin ich mir bewusst, dass das Timeout nur für die Verbindung ist, "Requests" scheint keinen Weg zu bieten, den Download abzubrechen. Ich mag die Idee von einem Thread pro Server, aber wenn der Thread hängt, wird der betreffende Server nicht mehr abgefragt. – dotancohen

+0

@dotancohen Weder Anfragen von urllib2 noch das Socket-Objekt, denke ich. Sie müssen also wahrscheinlich [socket.setdefaulttimeout] (http://docs.python.org/2/library/socket.html#socket.setdefaulttimeout) einrichten, um das I/O-Betriebszeitlimit * kurz vor dem * Öffnen der Verbindung (und wahrscheinlich danach zurücksetzen). Was die Verwendung eines Thread-Pools anbelangt, war mein * rate *, wenn ein Server eine eingehende Anfrage von einem Thread blockiert, wird er alle nachfolgenden Verbindungsversuche blockieren. aber vielleicht hängen Fäden "zufällig"? –

+0

Danke Sylvain, ich schaue mir das Socket-Timeout an. Schöner Fund! Die Server erlauben nachfolgende Verbindungen, andernfalls könnten die folgenden Threads sie nicht abfragen. Ich weiß wirklich nicht, was das Auflegen verursacht oder wo ich anfangen soll, es zu debuggen. – dotancohen

Verwandte Themen