Ich schreibe ein Skript (multi-threaded), um Inhalte von einer Website abzurufen, und die Seite ist nicht sehr stabil, so dass hin und wieder die HTTP-Anfrage hängt, die nicht einmal von socket.setdefaulttimeout()
zeitgesteuert werden kann. Da ich keine Kontrolle über diese Website habe, kann ich nur meine Codes verbessern, aber mir gehen gerade die Ideen aus.
Beispielcodes:
%Vor% Was muss ich tun, um die hängende Anfrage zu beenden? Eigentlich möchte ich wissen, warum socket.setdefaulttimeout(150)
überhaupt nicht funktioniert. Kann mir jemand helfen?
Hinzugefügt: (und ja Problem immer noch nicht gelöst)
OK, ich habe den Vorschlag von Tomasz befolgt und die Codes in MechBrowser.open(Request, timeout = 60)
geändert, aber es passiert dasselbe. Ich habe bis jetzt immer noch hängende Anfragen, manchmal sind es mehrere Stunden und manchmal mehrere Tage. Was mache ich jetzt? Gibt es eine Möglichkeit, diese hängenden Anfragen aufzugeben?
Während socket.setsocketimeout
das Standard-Zeitlimit für neue Sockets festlegt, können Sie die Einstellung leicht überschreiben, wenn Sie die Sockets nicht direkt verwenden. Insbesondere, wenn die Bibliothek socket.setblocking
an ihrem Socket aufruft, wird das Timeout zurückgesetzt.
urllib2.open
hat ein Timeout-Argument, hovewer, es gibt kein Timeout in urllib2.Request
. Da Sie mechanize
verwenden, sollten Sie auf ihre Dokumentation verweisen:
Seit Python 2.6 verwendet urllib2 intern das Attribut .timeout für Request-Objekte. Urllib2.Request hat jedoch kein Timeout-Konstruktorargument und urllib2.urlopen () ignoriert diesen Parameter. mechanize.Request hat ein Timeout-Konstruktorargument, mit dem das Attribut mit demselben Namen festgelegt wird, und mechanize.urlopen () ignoriert das Timeoutattribut nicht.
Quelle: Ссылка
--- BEARBEITEN ---
Wenn entweder socket.setsockettimeout
oder passing timeout auf mechanize
mit kleinen Werten arbeitet, aber nicht mit höheren Werten, kann die Ursache des Problems völlig anders sein. Eine Sache ist, dass Ihre Bibliothek mehrere Verbindungen öffnen kann (hier Kredit an @ Cédric Julien), so dass das Timeout für jeden einzelnen Versuch von socket.open gilt und wenn es nicht beim ersten Fehler aufhört - bis zu timeout * num_of_conn
Sekunden dauern kann. Die andere Sache ist socket.recv
: Wenn die Verbindung wirklich langsam ist und Sie Pech haben, kann die gesamte Anfrage bis zu timeout * incoming_bytes
dauern, da wir mit jedem socket.recv
ein Byte bekommen könnten, und jeder dieser Aufrufe könnte timeout
Sekunden. Da es unwahrscheinlich ist, dass Sie unter genau diesem dunklen Szenario leiden (ein Byte pro Timeout-Sekunden - Sie müssten ein sehr unhöflicher Junge sein), ist es sehr wahrscheinlich, dass Sie lange Zeit für sehr langsame Verbindungen und sehr hohe Timeouts brauchen.
Die einzige Lösung, die Sie haben, ist, die Zeitüberschreitung für die gesamte Anfrage zu erzwingen, aber hier gibt es nichts mit Sockets zu tun. Wenn Sie mit Unix arbeiten, können Sie eine einfache Lösung mit ALARM
signal verwenden. Sie setzen das Signal in timeout
Sekunden und Ihre Anfrage wird beendet (vergessen Sie nicht, es zu fangen). Möglicherweise möchten Sie die Anweisung with
verwenden, um sie sauber und einfach zu verwenden, zum Beispiel:
Wenn Sie portabler sein möchten, müssen Sie einige größere Waffen verwenden, zum Beispiel multiprocessing
, so dass Sie einen Prozess starten, um Ihre Anfrage aufzurufen und sie zu beenden, wenn sie überfällig ist. Da dies ein separater Prozess wäre, müssen Sie etwas verwenden, um das Ergebnis zurück in Ihre Anwendung zu übertragen, möglicherweise multiprocessing.Pipe
. Hier kommt das Beispiel:
Sie haben wirklich nicht viel Auswahl, wenn Sie die Anfrage nach einer festgelegten Anzahl von Sekunden beenden wollen. socket.timeout
wird ein Zeitlimit für einzelne Socket-Operationen bereitstellen (connect / recv / send), aber wenn Sie mehrere davon haben, können Sie unter sehr langer Ausführungszeit leiden.
Aus ihrer Dokumentation:
Seit Python 2.6 verwendet urllib2 ein Timeout-Attribut für Request-Objekte im Inneren. Urllib2.Request hat jedoch keinen Zeitüberschreitungskonstruktor Argument und urllib2.urlopen () ignoriert diesen Parameter. mechanize.Request hat ein Timeout-Konstruktorargument, das verwendet wird Legen Sie das Attribut mit dem gleichen Namen fest, und mechanize.urlopen () nicht Ignoriere das Timeout-Attribut.
Vielleicht sollten Sie versuchen, urllib2.Request durch mechanize.Request zu ersetzen.
Sie könnten versuchen, mechanize with eventlet zu verwenden. Es löst nicht Ihr Timeout-Problem, aber Greenlet blockiert nicht, so dass es Ihr Leistungsproblem lösen kann.