<p>aiohttp seharusnya tidak memanggil penangan pengecualian untuk situasi yang tidak dapat diterima</p>

Dibuat pada 10 Nov 2020  ·  4Komentar  ·  Sumber: aio-libs/aiohttp

🐞 Jelaskan bugnya
Ketika objek tertentu dari aiohttp bocor, mereka memanggil penangan pengecualian asyncio, yang di beberapa lingkungan (misalnya saat menggunakan aiorun , dengan stop_on_unhandled_errors=True ) berarti seluruh program dihentikan.

Misalnya, berikut adalah kode yang relevan di ClientResponse :

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

💡 Untuk Bereproduksi
Membocorkan objek aiohttp yang melakukan ini.

💡 Perilaku yang diharapkan
Objek bocor seharusnya tidak menyebabkan pengecualian, karena alasan yang sama bahwa open() ing file dan bukan .close() ing tidak memunculkan pengecualian.

Semua objek yang melakukan ini tampaknya sudah memunculkan peringatan tentang kebocoran sumber daya - Saya tidak melihat alasan mereka untuk memanggil penangan pengecualian juga.

📋 Versi Python Anda

$ python --version
Python 3.8.6

📋 Versi distribusi aiohttp / yarl / multidict Anda

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

`` konsol
$ python -m pip show multidict
Nama: multidict
Versi: 4.7.6.0

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

📋 Konteks tambahan
cjrh / aiorun # 56

bug wontfix

Semua 4 komentar

Saya tidak setuju.
Sumber daya yang tidak ditutup adalah kesalahan pemrograman yang cukup serius yang dapat diperbaiki dengan mudah dengan menulis kode yang benar.
Misalnya, asyncio itu sendiri menggunakan call_exception_handler() untuk melaporkan tentang panggilan asinkron yang tidak ditunggu.
Jika Anda tidak ingin menulis kode bertele-tele - Anda dapat menggunakan stop_on_unhandled_errors=False .

Jadi, mengapa tidak mengajukan pengecualian nyata?

Saya kira karena meningkatkan pengecualian di __del__ akan diabaikan. Tapi memang seharusnya begitu, bukan? Sangat sulit untuk men-debug "sesuatu mengalokasikan objek dan tidak menutupnya dengan benar", terutama ketika bug tidak ada dalam kode Anda sendiri tetapi di beberapa perpustakaan; kunci konteks source_traceback tidak terdokumentasi, dan tampaknya tidak bersahabat untuk mengandalkan perilaku tidak terdokumentasi dari penangan pengecualian default asyncio untuk memungkinkan men-debug kebocoran memori.

Saya juga tidak melihat di mana asyncio menggunakan call_exception_handler() untuk memperingatkan tentang coroutine yang tidak ditunggu. Ketika coroutine yang tidak ditunggu dikumpulkan sampah, itu memanggil _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);
    }

yang meminta warnings._warn_unawaited_coroutine() :

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

yang mengeluarkan RuntimeWarning. Saya tidak melihat call_exception_handler() digunakan di mana pun di sana - sebenarnya saya tidak melihat penggunaan call_exception_handler() di stdlib yang tidak menyertakan exception dalam konteksnya.

Dan lagi: jika lupa menutup file tidak menimbulkan pengecualian, mengapa harus lupa membersihkan objek aiohttp acak apa pun?

Anda benar, mengajukan pengecualian dari metode __del__ adalah praktik yang tidak disarankan.
Itu sebabnya kami membutuhkan solusi pensinyalan lain.
Asyncio memang memanggil call_exception_handler() dari __del__ , lihat Task.__del__ misalnya: https://github.com/python/cpython/blob/master/Lib/asyncio/tasks.py # L139 -L148

Anda benar, source_traceback tidak didokumentasikan di https://docs.python.org/3/library/asyncio-eventloop.html?highlight=call_exception_handler#asyncio.loop.call_exception_handler
Maukah Anda membuat permintaan tarik di https://github.com/python/cpython/ untuk memperbaiki dokumentasi? Saya senang mereview / menggabungkannya.

Dan lagi: jika lupa menutup file tidak menimbulkan pengecualian, mengapa harus lupa membersihkan objek aiohttp acak apa pun?

aiohttp tidak memunculkan eksepsi dari __del__ juga, itu hanya tidak mungkin di Python karena pemanggilan object finalizer tidak dapat ditentukan.

File yang tidak ditutup menghasilkan ResourceWarning . Peringatan ini diabaikan secara default: https://docs.python.org/3/library/warnings.html#default -warning-filter
Itulah mengapa jenis peringatan ini tidak terlihat oleh banyak pengembang jika mereka tidak mengaktifkannya secara eksplisit. Hal ini dilakukan sebagian karena alasan historis: untuk waktu yang lama jenis peringatan ini tidak ada, banyak pustaka tidak memanggil file.close() karena pembuatnya tidak menyadari perlunya pembersihan sumber daya yang anggun, dll., Dll. .

Untungnya, file.close() dapat dipanggil dari file.__del__ dengan aman, ini adalah panggilan biasa.
Tetapi di dunia asyncio close() sangat sering berbeda: ini harus berupa fungsi asinkron yang tidak dapat dipanggil dari __del__ .
Misalnya, transport.close() tanpa menunggu protocol.connection_lost() mengarah ke peringatan bahkan untuk soket biasa; untuk SSL situasinya bahkan lebih buruk.
aiohttp memiliki sedikit kekacauan dengan sinkronisasi / penyelesaian asinkron tetapi saya sedang mengerjakannya; aiohttp 4.0 harus dibersihkan secara signifikan.

Itulah mengapa pembersihan sangat penting, peringatan harus dimunculkan, dan call_exception_handler() akan digunakan untuk membuat penggunaan yang buruk lebih terlihat.

Asyncio _does_ menelepon call_exception_handler() dari __del__ , lihat Task.__del__ misalnya

Cukup adil, saya melewatkan panggilan itu.

Maukah Anda membuat permintaan tarik pada python / cpython untuk memperbaiki dokumentasi?

Sejujurnya saya tidak yakin bagaimana cara terbaik untuk mendokumentasikannya. Saya membuat bpo-42347 karena saya melihat beberapa perbedaan lain antara dokumen, docstring, dan implementasinya.

Itulah mengapa pembersihan sangat penting, peringatan harus dimunculkan, dan call_exception_handler () akan digunakan untuk membuat penggunaan yang buruk lebih terlihat.

Saya kira, itu hanya membuat frustrasi ketika Anda mendapatkan kesalahan karena perpustakaan yang Anda gunakan tidak membersihkan dirinya sendiri dengan benar. Saya tidak menyadari itu sangat penting sehingga harus menghentikan aplikasi, dan saya awalnya bahkan tidak menyadari bahwa kebocoran adalah alasan aiorun menghentikan loop.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat