<p>aiohttp sollte den Ausnahmebehandler nicht für außergewöhnliche Situationen aufrufen</p>

Erstellt am 10. Nov. 2020  ·  4Kommentare  ·  Quelle: aio-libs/aiohttp

🐞 Beschreiben Sie den Fehler
Wenn bestimmte Objekte von aiohttp durchgesickert sind, rufen sie den Asyncio-Ausnahmebehandler auf. In einigen Umgebungen (z. B. bei Verwendung von aiorun mit stop_on_unhandled_errors=True ) wird das gesamte Programm gestoppt.

Hier ist zum Beispiel der relevante Code in ClientResponse :

https://github.com/aio-libs/aiohttp/blob/a8d9ec3f1667463e80545b1cacc7833d1ff305e9/aiohttp/client_reqrep.py#L748 -L751

💡 Reproduzieren
Leck ein aiohttp-Objekt, das dies tut.

💡 Erwartetes Verhalten
Undichte Objekte sollten keine Ausnahme verursachen, aus dem gleichen Grund, aus dem open() eine Datei und nicht .close() keine Ausnahme auslöst.

Alle Objekte, die dies tun, scheinen bereits eine Warnung über den Ressourcenverlust auszulösen. Ich sehe keinen Grund für sie, auch den Ausnahmebehandler aufzurufen.

📋 Ihre Version von Python

$ python --version
Python 3.8.6

📋 Ihre Version der Distributionen aiohttp / yarl / multidict

$ python -m pip show aiohttp
Name: aiohttp
Version: 3.6.2

`` `Konsole
$ python -m pip show multidict
Name: Multidict
Version: 4.7.6

```console
$ python -m pip show yarl
Name: yarl
Version: 1.5.1

📋 Zusätzlicher Kontext
cjrh / aiorun # 56

bug wontfix

Alle 4 Kommentare

Ich bin nicht einverstanden.
Die nicht geschlossene Ressource ist ein schwerwiegender Programmierfehler, der leicht durch Schreiben des richtigen Codes behoben werden kann.
Beispielsweise verwendet Asyncio selbst call_exception_handler() um über unerwünschte asynchrone Aufrufe zu berichten.
Wenn Sie keinen pedantischen Code schreiben möchten, können Sie stop_on_unhandled_errors=False .

Warum also nicht eine echte Ausnahme machen?

Ich denke, weil das Auslösen einer Ausnahme in __del__ ignoriert wird. Aber so sollte es sein, nein? Es ist sehr schwierig zu debuggen, "etwas ordnet ein Objekt zu und schließt es nicht richtig", insbesondere wenn sich der Fehler nicht in Ihrem eigenen Code, sondern in einer Bibliothek befindet. Der Kontextschlüssel source_traceback ist nicht dokumentiert, und es scheint unfreundlich, sich auf das nicht dokumentierte Verhalten des Standard-Ausnahmebehandlungsprogramms von asyncio zu verlassen, um das Debuggen von Speicherlecks zu ermöglichen.

Ich sehe auch nicht, wo Asyncio call_exception_handler() , um vor unerwarteten Coroutinen zu warnen. Wenn eine unerwartete Coroutine mit Müll gesammelt wird, ruft sie _PyErr_WarnUnawaitedCoroutine :

    /* If `gen` is a coroutine, and if it was never awaited on,
       issue a RuntimeWarning. */
    if (gen->gi_code != NULL &&
        ((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE &&
        gen->gi_frame->f_lasti == -1)
    {
        _PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
    }

welches warnings._warn_unawaited_coroutine() aufruft:

void
_PyErr_WarnUnawaitedCoroutine(PyObject *coro)
{
    /* First, we attempt to funnel the warning through
       warnings._warn_unawaited_coroutine.

welches eine RuntimeWarning ausgibt. Ich sehe nicht, dass call_exception_handler() irgendwo dort verwendet wird - tatsächlich sehe ich keine Verwendung von call_exception_handler() in stdlib, die exception im Kontext enthält.

Und noch einmal: Wenn das Vergessen, eine Datei zu schließen, keine Ausnahme auslöst, warum sollte man dann vergessen, ein beliebiges zufälliges aiohttp-Objekt zu bereinigen?

Sie haben Recht, eine Ausnahme von der __del__ -Methode auszulösen, ist eine entmutigte Praxis.
Deshalb brauchen wir eine andere Signalisierungslösung.
Asyncio tut Anruf call_exception_handler() von __del__ , siehe Task.__del__ zum Beispiel: https://github.com/python/cpython/blob/master/Lib/asyncio/tasks.py # L139 -L148

Sie haben Recht, source_traceback ist nicht in https://docs.python.org/3/library/asyncio-eventloop.html?highlight=call_exception_handler#asyncio.loop.call_exception_handler dokumentiert
Würde es Ihnen etwas ausmachen, eine Pull-Anfrage unter https://github.com/python/cpython/ zu erstellen, um die Dokumentation zu reparieren? Ich freue mich, es zu überprüfen / zusammenzuführen.

Und noch einmal: Wenn das Vergessen, eine Datei zu schließen, keine Ausnahme auslöst, warum sollte man dann vergessen, ein beliebiges zufälliges aiohttp-Objekt zu bereinigen?

aiohttp keine Ausnahme von erhöhen __del__ zu, es ist einfach unmöglich , in Python ist , weil die Forderung des Objekts Finalizerthread indeterministischen ist.

Nicht geschlossene Datei erhöht ResourceWarning . Diese Warnung wird standardmäßig ignoriert: https://docs.python.org/3/library/warnings.html#default -warning-filter
Aus diesem Grund ist diese Art von Warnungen für sehr viele Entwickler nicht sichtbar, wenn sie nicht explizit aktiviert werden. Dies geschieht teilweise aus historischen Gründen: Lange Zeit gab es diese Art von Warnung nicht, viele Bibliotheken rufen nicht file.close() weil ihre Autoren sich der Notwendigkeit einer ordnungsgemäßen Bereinigung von Ressourcen usw. usw. .

Zum Glück, file.close() könnte von heißen file.__del__ sicher, ist es ein regelmäßiger Anruf.
Aber in der Asyncio-Welt ist close() sehr oft anders: Es muss eine Async-Funktion sein, die einfach nicht von __del__ aufgerufen werden kann.
Zum Beispiel führt transport.close() ohne Warten auf protocol.connection_lost() zu Warnungen, selbst bei einfachen Steckdosen. Für SSL ist die Situation noch schlimmer.
aiohttp hat ein kleines Durcheinander mit Sync / Async-Finalisierern, aber ich arbeite daran. aiohttp 4.0 sollte deutlich aufgeräumt werden.

Aus diesem Grund ist die Bereinigung sehr wichtig. Es sollte eine Warnung ausgegeben werden, und call_exception_handler() wird verwendet, um die schlechte Verwendung besser sichtbar zu machen.

Asyncio ruft call_exception_handler() von __del__ , siehe zum Beispiel Task.__del__

Fair genug, ich habe diesen Anruf verpasst.

Würde es Ihnen etwas ausmachen, eine Pull-Anfrage für Python / Python zu erstellen, um die Dokumentation zu reparieren?

Ich bin mir ehrlich gesagt nicht sicher, wie ich es am besten dokumentieren soll. Ich habe bpo-42347 erstellt, da ich einige andere Diskrepanzen zwischen den Dokumenten, der Dokumentzeichenfolge und der Implementierung festgestellt habe.

Aus diesem Grund ist die Bereinigung sehr wichtig. Es sollte eine Warnung ausgegeben werden, und call_exception_handler () wird verwendet, um die fehlerhafte Verwendung besser sichtbar zu machen.

Ich denke, es ist nur frustrierend, wenn Sie Fehler erhalten, weil eine Bibliothek, die Sie verwenden, nicht richtig nach sich selbst bereinigt. Ich wusste nicht, dass es so wichtig ist, dass es die Anwendung stoppen sollte, und ich wusste anfangs nicht einmal, dass das Leck der Grund war, warum aiorun die Schleife stoppte.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen