Requests: batas waktu keseluruhan

Dibuat pada 16 Apr 2016  ·  38Komentar  ·  Sumber: psf/requests

Kami telah memanfaatkan parameter batas waktu yang memungkinkan pengaturan per batas waktu transaksi TCP. Ini sangat membantu! Namun, kami juga perlu mendukung batas waktu keseluruhan di seluruh koneksi. Membaca dokumen tentang batas waktu Saya melihat ini saat ini tidak didukung, dan mencari melalui masalah setidaknya sedikit ke belakang saya tidak melihat permintaan lain untuk fitur ini -- permisi jika ada.

Saya menyadari bahwa kami dapat menyetel penghitung waktu di perpustakaan kami untuk mencapai ini, tetapi saya khawatir tentang overhead tambahan (satu per utas, dan kami mungkin memiliki banyak) serta efek buruk apa pun pada penyatuan koneksi jika kami akhirnya perlu membatalkan a meminta. Apakah ada cara yang baik untuk membatalkan permintaan? Saya tidak melihat sesuatu yang jelas di dokumen.

Jadi: Jangka panjang, akan sangat bagus jika kita bisa menambahkan batas waktu keseluruhan ke perpustakaan permintaan. Jangka pendek, apakah ada cara yang disarankan untuk menerapkan ini di pihak saya?

Propose Close

Komentar yang paling membantu

@jribbens Ada beberapa masalah dengan ini.

Bagian 1 adalah bahwa kompleksitas tambalan semacam itu sangat tinggi. Agar berfungsi dengan benar, Anda perlu berulang kali mengubah batas waktu pada level soket. Ini berarti bahwa tambalan harus diteruskan secara luas melalui httplib, yang telah kami tambal lebih dari yang kami inginkan. Pada dasarnya, kita perlu menjangkau httplib dan menerapkan kembali sekitar 50% dari metode yang lebih kompleks untuk mencapai perubahan fungsional ini.

Bagian 2 adalah bahwa pemeliharaan patch semacam itu relatif memberatkan. Kami mungkin perlu mulai mempertahankan jumlah garpu paralel httplib (lebih tepatnya http.client saat ini) agar berhasil melakukannya. Atau, kita perlu menanggung beban pemeliharaan tumpukan HTTP berbeda yang lebih dapat menerima perubahan semacam ini. Bagian ini, saya kira, biasanya terlewatkan oleh mereka yang ingin memiliki fitur seperti itu: biaya penerapannya tinggi, tetapi itu _tidak ada apa-apanya_ dibandingkan dengan biaya pemeliharaan berkelanjutan untuk mendukung fitur tersebut di semua platform.

Bagian 3 adalah bahwa keuntungan dari patch tersebut tidak jelas. Menurut pengalaman saya, kebanyakan orang yang menginginkan patch timeout total tidak sepenuhnya berpikir jernih tentang apa yang mereka inginkan. Dalam kebanyakan kasus, parameter batas waktu total akhirnya memiliki efek mematikan permintaan yang sangat bagus tanpa alasan.

Misalnya, Anda telah merancang sedikit kode yang mengunduh file, dan Anda ingin menangani hang. Meskipun awalnya tergoda untuk ingin menetapkan batas waktu total tetap ("tidak ada permintaan yang memerlukan waktu lebih dari 30 detik!"), batas waktu seperti itu tidak tepat sasaran. Misalnya, jika file berubah dari ukuran 30MB menjadi 30GB, file tersebut _tidak pernah_ dapat diunduh dalam interval waktu seperti itu, meskipun unduhan mungkin sepenuhnya sehat.

Dengan kata lain, batas waktu total adalah gangguan yang menarik: tampaknya menyelesaikan masalah, tetapi tidak melakukannya secara efektif. Pendekatan yang lebih berguna, menurut pendapat saya, adalah memanfaatkan batas waktu tindakan per soket, dikombinasikan dengan stream=True dan iter_content , dan menetapkan batas waktu sendiri untuk potongan data. Cara kerja iter_content , aliran kontrol akan dikembalikan ke kode Anda dalam interval yang agak teratur. Itu berarti bahwa Anda dapat mengatur sendiri batas waktu tingkat soket (mis. 5 detik) dan kemudian iter_content melalui potongan yang cukup kecil (mis. data 1KB) dan relatif yakin bahwa kecuali Anda sedang diserang secara aktif, tidak ada penolakan layanan mungkin di sini. Jika Anda benar-benar khawatir tentang penolakan layanan, setel batas waktu tingkat soket Anda jauh lebih rendah dan ukuran potongan Anda lebih kecil (0,5 detik dan 512 byte) untuk memastikan bahwa Anda secara teratur memiliki aliran kontrol yang dikembalikan kepada Anda.

Hasil dari semua ini adalah saya percaya bahwa batas waktu total adalah fitur yang salah di perpustakaan seperti ini. Jenis batas waktu terbaik adalah yang disetel untuk memungkinkan respons yang cukup besar waktu untuk mengunduh dengan tenang, dan batas waktu seperti itu paling baik dilayani oleh batas waktu tingkat soket dan iter_content .

Semua 38 komentar

Hai @emgerner-msft,

Untuk referensi, berikut adalah semua variasi pada tema ini jika bukan permintaan fitur yang tepat ini:

Kami juga telah membahas ini di https://github.com/sigmavirus24/requests-toolbelt/issues/51

Anda akan melihat tautan terakhir membahas paket ini yang seharusnya menangani ini untuk Anda tanpa menambahkannya ke permintaan. Kenyataannya, tidak perlu ada permintaan untuk melakukan ini ketika paket lain sudah melakukannya dengan sangat baik.

Paket yang Anda rujuk melakukannya dengan melakukan proses terpisah untuk menjalankan permintaan web. Itu adalah cara yang sangat berat untuk mencapai tujuan sederhana dari batas waktu, dan menurut saya sama sekali bukan pengganti permintaan itu sendiri yang memiliki fitur batas waktu asli.

@jribbens Jika Anda dapat menemukan cara yang tidak menggunakan utas atau proses, itu akan luar biasa. Sampai saat itu, jika Anda ingin jam dinding habis, taruhan terbaik Anda adalah paket itu karena ini adalah cara paling andal untuk mencapainya saat ini.

Saya tidak berpikir @jribbens mengatakan tidak ada utas atau proses. Hanya saja sebuah proses _per_ web request yang berlebihan. Banyak bahasa memiliki cara beberapa penghitung waktu berbagi satu utas atau proses tambahan. Saya hanya tidak tahu bagaimana melakukan yang terbaik dengan Python.

Sepertinya #1928 memiliki diskusi alternatif paling banyak, tetapi sebagian besar datang dengan banyak peringatan (ini tidak akan berfungsi untuk kasus penggunaan Anda, dll). Saya baik-baik saja dengan memiliki beberapa kode khusus di perpustakaan saya dan menulis solusi khusus saya sendiri jika ini benar-benar tidak termasuk dalam permintaan, tetapi saya pikir saya perlu sedikit lebih banyak informasi tentang seperti apa bentuknya. Seluruh alasan kami menggunakan permintaan adalah untuk menjauh dari logika penyatuan koneksi TCP tingkat rendah tetapi sepertinya membaca utas itu bahwa untuk menulis kode khusus ini saya perlu mengetahui logika itu, dan itulah yang membuat saya bermasalah .

@emgerner-msft benar. Saya agak bingung dengan komentar @ sigmavirus24 , memiliki "waktu habis total" tanpa menggunakan utas atau proses tampaknya cukup pejalan kaki dan sama sekali tidak "luar biasa". Hitung saja tenggat waktu di awal seluruh proses (misalnya deadline = time.time() + total_timeout ) dan kemudian pada setiap operasi atur batas waktu menjadi deadline - time.time() .

memiliki "batas waktu total" tanpa menggunakan utas atau proses tampaknya cukup pejalan kaki dan sama sekali tidak "luar biasa".

Dan solusi Anda agak primitif. Alasan _kebanyakan_ orang menginginkan batas waktu total (atau jam dinding) adalah untuk mencegah pembacaan "menggantung", dengan kata lain kasus seperti berikut:

r = requests.get(url, stream=True)
for chunk in r.iter_content(chunksize):
    process_data(chunk)

Di mana setiap pembacaan membutuhkan waktu lama di tengah iter_content tetapi itu kurang dari batas waktu baca (saya berasumsi kami menerapkannya saat streaming, tetapi mungkin masih kami tidak melakukannya) yang mereka tentukan . Tentu saja sepertinya ini harus ditangani dengan solusi Anda @jribbens sampai Anda ingat bagaimana jam melayang dan waktu musim panas bekerja dan mereka time.time() sangat tidak mencukupi.

Terakhir, penting untuk diingat bahwa API Permintaan dibekukan. Tidak ada API yang baik atau konsisten untuk menentukan batas waktu total. Dan jika kami menerapkan batas waktu seperti yang Anda sarankan, kami akan memiliki banyak bug yang mereka tentukan waktu tunggu total satu menit tetapi butuh waktu lebih lama karena terakhir kali kami memeriksa kami berada di bawah satu menit tetapi batas waktu baca yang dikonfigurasi cukup lama sehingga batas waktu mereka kesalahan dinaikkan sekitar satu setengah menit. Itu _sangat_ batas waktu dinding kasar yang akan sedikit lebih baik bagi orang yang mencari ini, tetapi tidak berbeda dari orang yang menerapkannya sendiri.

Maaf jika saya tidak jelas @sigmavirus24 , Anda tampaknya telah mengkritik prinsip ilustrasi pseudocode saya seolah-olah Anda mengira itu adalah tambalan literal. Saya harus menunjukkan bahwa time.time() tidak bekerja seperti yang Anda pikirkan - waktu musim panas tidak relevan, dan jam juga tidak miring pada rentang waktu yang sedang kita bicarakan di sini. Anda juga telah salah memahami saran tersebut jika menurut Anda bug yang Anda gambarkan akan terjadi. Akhirnya saya tidak yakin apa yang Anda maksud dengan API Permintaan yang "dibekukan" karena API diubah baru-baru ini sebagai versi 2.9.0 jadi jelas apa pun yang Anda maksudkan, itu bukan yang biasanya saya pahami dengan kata tersebut.

Hanya untuk memisahkan diskusi saya: Saya sebenarnya tidak berdebat ini mudah. Jika itu benar-benar sederhana, saya hanya akan menulisnya dan berhenti mengganggu Anda. :)

Masalah saya adalah:
1) Semua yang ada di utas yang Anda daftarkan adalah tambalan monyet. Tidak apa-apa, tetapi saya menggunakan ini di perpustakaan kualitas produksi dan tidak dapat menerima peringatan perubahan internal yang merusak segalanya.
2) Dekorator batas waktu di tautan yang Anda berikan sangat bagus, tetapi saya tidak jelas bagaimana hal itu memengaruhi koneksi. Bahkan jika kami menerima bahwa satu-satunya cara yang baik untuk melakukan batas waktu adalah dengan sekelompok utas, bagaimana perpustakaan ini menegakkan bahwa soket dimatikan, koneksi terputus, dll. Kami melakukan banyak koneksi dan ini tampaknya berpotensi cukup rawan bocor. permintaan tidak memiliki metode 'batalkan' yang dapat saya temukan (koreksi saya jika saya salah) jadi bagaimana pemutusan koneksi terjadi?

Yang saya cari hanyalah versi 'diberkati' yang jelas tentang bagaimana menyelesaikan masalah ini sendiri, atau jika tidak ada solusi yang sempurna, beberapa solusi dengan peringatan yang dibahas. Apakah itu masuk akal?

@emgerner-msft Dengan asumsi Anda menggunakan CPython, pemutusan koneksi akan terjadi ketika permintaan tidak lagi dilanjutkan. Pada saat itu semua referensi ke koneksi yang mendasarinya akan hilang dan soket akan ditutup dan dibuang.

@Lukasa Oke, terima kasih! Bagaimana perpustakaan menentukan permintaan tidak lagi berlanjut? Misalnya, jika saya menggunakan rute dekorator batas waktu dan terputus di tengah unduhan, kapan unduhan benar-benar berhenti? Apakah saya perlu melakukan sesuatu yang istimewa dengan opsi streaming?

Jika Anda menggunakan dekorator batas waktu, unduhan akan berhenti saat batas waktu menyala. Ini karena sinyal mengganggu syscalls, yang berarti tidak akan ada panggilan lagi ke soket. Setelah permintaan tidak lagi dalam cakupan (misalnya tumpukan telah dibatalkan ke luar fungsi requests.* Anda), yaitu di: CPython akan membersihkan objek koneksi dan meruntuhkan koneksi. Tidak diperlukan opsi streaming khusus di sana.

Sempurna. Saya baik untuk menutup utas itu, kecuali orang lain memiliki lebih banyak untuk dikatakan.

Sebenarnya, maaf, satu lagi kekhawatiran. Sedang melihat kode dekorator batas waktu lebih dekat karena Anda mengatakan bahwa itu menggunakan sinyal relevan, sebagai lawan dari sesuatu seperti Python Timer (mungkin). Sepertinya itu memanggil sinyal dengan SIGALRM yang didokumentasikan dalam Python Signal tidak berfungsi di Windows. Saya membutuhkan ini untuk bekerja di lingkungan Unix dan Windows, serta di Python 2.7 dan 3.3+ (seperti permintaan itu sendiri). Saya akan melihat-lihat sedikit lebih banyak dan melihat apakah ini benar-benar akan berhasil mengingat itu.

@emgerner-msft Itu membuat frustrasi. =(

@Lukasa Yup, mencoba cuplikan penggunaan dasar dan tidak berfungsi di Windows. Saya membaca lebih banyak kode/contoh dan mengutak-atik dan sepertinya jika kita tidak menggunakan sinyal, paket mungkin berfungsi, tetapi semuanya harus dapat dipilih yang tidak berlaku untuk aplikasi saya. Sejauh yang saya tahu, dekorator batas waktu tidak akan menyelesaikan masalah saya. Ada ide lain?

@emgerner-msft Apakah Anda yakin bahwa tidak ada sinyal khusus Windows yang cocok?

@Lukasa Terus terang, saya tidak tahu. Saya belum pernah menggunakan sinyal sebelumnya, dan sepertinya saya tidak menyadarinya sampai Anda memberi tahu saya bahwa mereka akan mengganggu permintaan. Saya tidak yakin apa yang pantas. Saya juga tidak mencoba agar ini hanya berfungsi di Windows. Saya membutuhkan dukungan crossplat penuh (Windows dan Unix) dan dukungan Python 2 dan Python 3. Begitu banyak sinyal yang terlihat spesifik pada platform sehingga membuat saya bingung. Timer adalah salah satu solusi yang saya lihat yang terlihat kurang rendah dan dengan demikian mungkin mengatasi kendala saya, tetapi saya tidak yakin bagaimana saya bisa menutup koneksi. Saya bisa lebih banyak membaca, tapi inilah mengapa saya berharap mendapat bimbingan tambahan dari kalian. :)

Jadi ini adalah tempat yang sangat sulit untuk menjadi.

Kenyataannya adalah bahwa kurang lebih tidak ada cara lintas platform untuk mematikan utas kecuali dengan menginterupsinya, yang pada dasarnya adalah sinyal. Itu artinya, menurut saya, sinyal adalah satu-satunya rute yang benar-benar Anda miliki untuk membuatnya bekerja di seluruh platform. Saya cenderung mencoba melakukan ping ke pakar Windowsy Pythony: @brettcannon , apakah Anda punya saran bagus di sini?

Karena minat, apakah ada alasan untuk tidak menerapkan "total batas waktu" dalam Permintaan selain dari penerapan dan pengujian yang memerlukan pekerjaan? Maksud saya, jika tambalan untuk mengimplementasikannya secara ajaib muncul hari ini, apakah secara teori akan ditolak atau diterima? Saya menghargai dan setuju dengan sudut pandang "hilangkan kerumitan yang tidak perlu", tetapi "Anda dapat melakukannya dengan melakukan proses terpisah" tidak membuat fitur ini tidak perlu menurut saya.

@jribbens Ada beberapa masalah dengan ini.

Bagian 1 adalah bahwa kompleksitas tambalan semacam itu sangat tinggi. Agar berfungsi dengan benar, Anda perlu berulang kali mengubah batas waktu pada level soket. Ini berarti bahwa tambalan harus diteruskan secara luas melalui httplib, yang telah kami tambal lebih dari yang kami inginkan. Pada dasarnya, kita perlu menjangkau httplib dan menerapkan kembali sekitar 50% dari metode yang lebih kompleks untuk mencapai perubahan fungsional ini.

Bagian 2 adalah bahwa pemeliharaan patch semacam itu relatif memberatkan. Kami mungkin perlu mulai mempertahankan jumlah garpu paralel httplib (lebih tepatnya http.client saat ini) agar berhasil melakukannya. Atau, kita perlu menanggung beban pemeliharaan tumpukan HTTP berbeda yang lebih dapat menerima perubahan semacam ini. Bagian ini, saya kira, biasanya terlewatkan oleh mereka yang ingin memiliki fitur seperti itu: biaya penerapannya tinggi, tetapi itu _tidak ada apa-apanya_ dibandingkan dengan biaya pemeliharaan berkelanjutan untuk mendukung fitur tersebut di semua platform.

Bagian 3 adalah bahwa keuntungan dari patch tersebut tidak jelas. Menurut pengalaman saya, kebanyakan orang yang menginginkan patch timeout total tidak sepenuhnya berpikir jernih tentang apa yang mereka inginkan. Dalam kebanyakan kasus, parameter batas waktu total akhirnya memiliki efek mematikan permintaan yang sangat bagus tanpa alasan.

Misalnya, Anda telah merancang sedikit kode yang mengunduh file, dan Anda ingin menangani hang. Meskipun awalnya tergoda untuk ingin menetapkan batas waktu total tetap ("tidak ada permintaan yang memerlukan waktu lebih dari 30 detik!"), batas waktu seperti itu tidak tepat sasaran. Misalnya, jika file berubah dari ukuran 30MB menjadi 30GB, file tersebut _tidak pernah_ dapat diunduh dalam interval waktu seperti itu, meskipun unduhan mungkin sepenuhnya sehat.

Dengan kata lain, batas waktu total adalah gangguan yang menarik: tampaknya menyelesaikan masalah, tetapi tidak melakukannya secara efektif. Pendekatan yang lebih berguna, menurut pendapat saya, adalah memanfaatkan batas waktu tindakan per soket, dikombinasikan dengan stream=True dan iter_content , dan menetapkan batas waktu sendiri untuk potongan data. Cara kerja iter_content , aliran kontrol akan dikembalikan ke kode Anda dalam interval yang agak teratur. Itu berarti bahwa Anda dapat mengatur sendiri batas waktu tingkat soket (mis. 5 detik) dan kemudian iter_content melalui potongan yang cukup kecil (mis. data 1KB) dan relatif yakin bahwa kecuali Anda sedang diserang secara aktif, tidak ada penolakan layanan mungkin di sini. Jika Anda benar-benar khawatir tentang penolakan layanan, setel batas waktu tingkat soket Anda jauh lebih rendah dan ukuran potongan Anda lebih kecil (0,5 detik dan 512 byte) untuk memastikan bahwa Anda secara teratur memiliki aliran kontrol yang dikembalikan kepada Anda.

Hasil dari semua ini adalah saya percaya bahwa batas waktu total adalah fitur yang salah di perpustakaan seperti ini. Jenis batas waktu terbaik adalah yang disetel untuk memungkinkan respons yang cukup besar waktu untuk mengunduh dengan tenang, dan batas waktu seperti itu paling baik dilayani oleh batas waktu tingkat soket dan iter_content .

Mungkin @zooba punya ide karena dia benar-benar tahu cara kerja Windows. :)

(Tidak terkait, salah satu hal favorit saya untuk dilakukan adalah menyiapkan rantai ahli dalam masalah GitHub.)

Haha, saya sudah tahu @zooba dan @brettcannon. Saya dapat berdiskusi dengan mereka di sini atau secara internal sebagai solusi untuk ini mungkin akan membantu mereka juga.

@ emgerner-msft Saya pikir Anda mungkin, tetapi tidak ingin menganggap: MSFT adalah organisasi besar!

@Lukasa Baru saja membaca dinding teks yang baru saja Anda tulis di atas -- menarik! Pada diskusi stream=True dan iter_content untuk unduhan waktu, apa cara yang setara untuk menangani unggahan yang lebih besar?

_PS_: Paragraf di atas yang dimulai dengan 'Let another way,..' adalah jenis panduan yang saya cari di dokumen. Mengingat jumlah permintaan yang Anda dapatkan untuk batas waktu maksimum (dan alasan sah Anda untuk tidak melakukannya), mungkin hal terbaik yang harus dilakukan adalah menambahkan beberapa informasi itu di dokumen batas waktu ?

lol @lukasa Saya mengambil poin Anda tentang pemeliharaan, yang sudah ada di pikiran saya, tetapi pada "fitur vs misfeature" saya khawatir saya benar-benar berlawanan dengan Anda. Saya pikir siapa pun yang _tidak_ menginginkan batas waktu total tidak berpikir jernih tentang apa yang mereka inginkan, dan saya mengalami kesulitan membayangkan situasi di mana apa yang Anda gambarkan sebagai bug "pengunduhan 30MB berubah menjadi 30GB dan karenanya gagal" tidak sebenarnya fitur yang bermanfaat!

Anda dapat seperti yang Anda katakan melakukan sesuatu yang sedikit mirip (tapi saya curiga tanpa sebagian besar manfaat dari total waktu habis) menggunakan stream=True tetapi saya pikir inti dari permintaan adalah bahwa itu menangani hal-hal untuk Anda ...

Saya pikir inti dari permintaan adalah bahwa itu menangani hal-hal untuk Anda

Ini menangani HTTP untuk Anda. Fakta bahwa kami telah menangani koneksi dan waktu tunggu baca dan bahwa kami memiliki beberapa pengecualian untuk pembekuan fitur kami selama beberapa tahun bersinggungan dengan diskusi tentang utilitas, keinginan, konsistensi (di berbagai platform), dan pemeliharaan. Kami menghargai umpan balik dan pendapat Anda. Jika Anda memiliki informasi baru untuk disajikan, kami akan sangat menghargainya.

Mungkin juga dikatakan bahwa permintaan tidak menangani semuanya, dengan jumlah permintaan fitur yang ditolak pada proyek ini dan fakta bahwa ada proyek terpisah yang menerapkan pola penggunaan umum untuk pengguna (permintaan toolbelt). Jika batas waktu total termasuk di mana saja, itu akan ada di sana, tetapi sekali lagi, itu harus bekerja pada Windows, BSD, Linux, dan OSX dengan cakupan pengujian yang sangat baik dan tanpa itu menjadi mimpi buruk untuk dipertahankan.

Pada diskusi stream=True dan iter_content untuk unduhan waktu, apa cara yang setara untuk menangani unggahan yang lebih besar?

Tentukan generator untuk unggahan Anda, dan teruskan ke data . Atau, jika penyandian chunked bukan pemenang untuk Anda, tentukan objek seperti file dengan metode read ajaib dan teruskan _that_ ke data .

Biarkan saya menguraikan sedikit. Jika Anda meneruskan generator ke data , permintaan akan mengulanginya, dan akan mengirimkan setiap potongan secara bergantian. Ini berarti bahwa untuk mengirim data, kami harus menyerahkan aliran kontrol ke kode Anda untuk setiap potongan. Ini memungkinkan Anda melakukan apa pun yang Anda inginkan dalam waktu itu, termasuk membuang pengecualian untuk membatalkan permintaan sama sekali.

Jika karena alasan tertentu Anda tidak dapat menggunakan penyandian transfer chunked untuk unggahan Anda (tidak mungkin, tetapi mungkin jika server yang dimaksud benar-benar buruk), Anda dapat melakukan hal yang sama dengan membuat objek seperti file yang memiliki panjang dan kemudian melakukan magic dalam panggilan read , yang akan dipanggil berulang kali untuk potongan 8192-byte. Sekali lagi, ini memastikan aliran kontrol melewati kode Anda sesekali, yang memungkinkan Anda menggunakan logika Anda sendiri.

PS: Paragraf di atas yang dimulai dengan 'Let another way,..' adalah jenis panduan yang saya cari di dokumen. Mengingat jumlah permintaan yang Anda dapatkan untuk batas waktu maksimum (dan alasan sah Anda untuk tidak melakukannya), mungkin hal terbaik yang harus dilakukan adalah menambahkan beberapa informasi itu di dokumen batas waktu?

Saya seharusnya_. Namun, secara umum, saya selalu gugup untuk memasukkan teks yang agak defensif ke dalam dokumentasi. Itu bisa masuk ke FAQ, saya kira, tetapi teks yang menjelaskan mengapa kami _tidak_ memiliki sesuatu jarang berguna dalam dokumentasi. Ruang di dokumen akan lebih baik dilayani, saya kira, dengan resep untuk melakukan sesuatu.

Saya pikir siapa pun yang tidak menginginkan batas waktu total tidak berpikir jernih tentang apa yang mereka inginkan, dan saya mengalami kesulitan membayangkan situasi di mana apa yang Anda gambarkan sebagai bug "unduhan 30MB berubah menjadi 30GB dan karenanya gagal" tidak sebenarnya fitur yang bermanfaat!

Hehe, saya tidak:

  • manajer paket (misalnya pip, yang menggunakan permintaan), di mana ukuran data paket dapat sangat bervariasi
  • scraper web, yang dapat berjalan melawan beberapa situs yang ukurannya sangat bervariasi
  • agregator log yang mengunduh file log dari host yang memiliki tingkat yang sangat bervariasi dari kami (dan karenanya ukuran file log)
  • pengunduh video (ukuran video dapat sangat bervariasi)

Pada kenyataannya, saya pikir kasus yang pengembang tahu dalam satu urutan besarnya ukuran file apa yang akan mereka tangani adalah kasus yang tidak biasa. Dalam kebanyakan kasus, pengembang tidak tahu. Dan secara umum saya akan mengatakan bahwa membuat asumsi tentang ukuran itu tidak bijaksana. Jika Anda memiliki batasan pada ukuran unduhan maka kode Anda harus dengan sengaja mengkodekan asumsi tersebut (misalnya dalam bentuk pemeriksaan pada panjang konten), daripada secara implisit menyandikannya dan mencampurnya dengan bandwidth jaringan pengguna sehingga orang lain membaca kode dapat melihatnya dengan jelas.

tapi saya pikir inti dari permintaan adalah bahwa itu menangani hal-hal untuk Anda ...

Permintaan dengan sangat sengaja tidak menangani semuanya untuk pengguna. Mencoba melakukan semuanya adalah tugas yang mustahil, dan tidak mungkin membangun perpustakaan bagus yang melakukan itu. Kami secara teratur memberi tahu pengguna untuk turun ke urllib3 untuk mencapai sesuatu.

Kami hanya memasukkan kode ke dalam permintaan jika kami dapat melakukannya dengan lebih baik atau lebih bersih daripada yang dapat dilakukan sebagian besar pengguna. Jika tidak, tidak ada nilainya. Saya benar-benar belum menjual total batas waktu menjadi salah satu dari hal-hal itu, terutama mengingat apa yang saya anggap sebagai utilitas yang relatif marjinal ketika dikumpulkan di seluruh basis pengguna kami.

Yang mengatakan, saya terbuka untuk diyakinkan bahwa saya salah: Saya hanya belum melihat argumen yang meyakinkan untuk itu (dan, untuk mencegah Anda, "Saya membutuhkannya!" bukanlah argumen yang meyakinkan: harus memberikan beberapa alasan!).

@sigmavirus24

Jika batas waktu total termasuk di mana saja, itu akan ada di sana, tetapi sekali lagi, itu harus bekerja pada Windows, BSD, Linux, dan OSX dengan cakupan pengujian yang sangat baik dan tanpa itu menjadi mimpi buruk untuk dipertahankan.

Sepakat!

@lukasa Saya kira pemikiran saya adalah bahwa saya tidak hanya menginginkannya, sebenarnya hampir semua pengguna menginginkannya jika mereka memikirkannya (atau mereka tidak menyadari itu belum ada). Setengah dari skenario penggunaan Anda di atas di mana Anda mengatakan itu harus dihindari Saya akan mengatakan itu penting (pengikis web dan agregator log) - dua lainnya kurang diperlukan karena kemungkinan ada pengguna yang menunggu hasil yang dapat membatalkan unduhan secara manual jika mereka ingin. Apa pun yang berjalan di latar belakang tanpa UI dan tidak menggunakan batas waktu keseluruhan menurut saya bermasalah!

Saya kira pemikiran saya adalah bahwa saya tidak hanya menginginkannya, pada kenyataannya hampir semua pengguna menginginkannya jika mereka memikirkannya (atau mereka tidak menyadari itu belum ada).

@jribbens kami memiliki beberapa tahun (lebih dari satu dekade jika Anda menggabungkan pengalaman kami bertiga) berbicara dengan dan memahami kebutuhan pengguna kami. Apa yang diperlukan untuk hampir semua (setidaknya 98%) pengguna adalah koneksi dan batas waktu baca. Kami memahami bahwa sebagian kecil pengguna kami yang sangat vokal menginginkan batas waktu keseluruhan. Mengingat apa yang dapat kami perkirakan sebagai ukuran grup pengguna potensial untuk fitur itu versus berapa ukuran potensial pengguna yang tidak membutuhkan fitur itu dan kompleksitas pemeliharaan dan pengembangan fitur, itu bukan sesuatu yang benar-benar kami tuju. melakukan.

Jika Anda memiliki sesuatu _baru_ untuk dibagikan, kami ingin mendengarnya, tetapi sejauh ini yang Anda katakan adalah bahwa menurut Anda apa pun yang menggunakan permintaan tanpa batas waktu keseluruhan adalah buggy dan saya dapat membayangkan bahwa ada banyak pengguna yang akan tersinggung dengan pernyataan Anda bahwa keputusan desain mereka bermasalah. Jadi, tolong jangan menghina kecerdasan pengguna kami.

@ sigmavirus24 Sepanjang utas ini Anda telah merendahkan, menghasut, dan kasar, dan saya meminta Anda dengan sopan, tolong berhenti.

@Lukasa Saya melihat secara detail saran Anda tentang cara melakukan streaming, unggah dan unduh, dan baca dokumen tentang topik ini. Jika Anda dapat memvalidasi asumsi/pertanyaan saya, itu akan bagus.

  1. Untuk pengunduhan streaming jika saya menggunakan sesuatu seperti batas waktu baca '(misalnya 5 detik) dan kemudian iter_content lebih dari potongan yang cukup kecil (misalnya 1KB data)', itu berarti perpustakaan permintaan akan menerapkan batas waktu 5 detik untuk setiap pembacaan 1KB dan batas waktu jika itu membutuhkan waktu lebih dari 5 detik. Benar?
  2. Untuk unggahan streaming jika saya menggunakan generator atau objek seperti file yang mengembalikan potongan data dan saya mengatur batas waktu baca ke 5 detik, perpustakaan permintaan akan menerapkan batas waktu 5 detik untuk setiap potongan yang saya kembalikan dan batas waktu jika butuh waktu lebih lama. Benar?
  3. Jika saya tidak menggunakan generator untuk mengunggah dan hanya meneruskan byte secara langsung, bagaimana perpustakaan permintaan memutuskan untuk menerapkan batas waktu baca yang saya tetapkan? Misalnya, jika saya melewati sepotong ukuran 4MB dan batas waktu baca 5 detik, kapan tepatnya batas waktu baca itu diterapkan?
  4. Jika saya tidak menggunakan iter_content dan hanya meminta permintaan mengunduh semua konten langsung ke dalam permintaan dengan batas waktu baca 5 detik, kapan tepatnya batas waktu baca diterapkan?

Saya memiliki pemahaman umum tentang soket/protokol TCP/dll tetapi tidak persis bagaimana urllib bekerja dengan konsep-konsep ini di tingkat yang lebih rendah atau jika permintaan melakukan sesuatu yang istimewa selain menurunkan nilai. Saya ingin memahami dengan tepat bagaimana batas waktu diterapkan karena hanya mendapatkan aliran kontrol kembali dan menerapkan skema batas waktu saya sendiri tidak berfungsi mengingat masalah crossplat dengan mengakhiri utas. Jika ada bahan bacaan tambahan untuk menjawab pertanyaan saya, jangan ragu untuk merujuk saya! Bagaimanapun, ini semoga menjadi pertanyaan terakhir saya. :)

Terima kasih atas bantuan Anda selama ini.

@emgerner-msft Oke:

  1. Tidak. Ini lebih kompleks dari itu, sayangnya. Seperti yang telah dibahas, setiap batas waktu berlaku _per panggilan soket_, tetapi kami tidak dapat menjamin berapa banyak panggilan soket dalam potongan tertentu. Alasan yang cukup kompleks untuk ini adalah bahwa pustaka standar membungkus soket pendukung dalam objek buffer (biasanya sesuatu seperti io.BufferedReader ). Itu akan membuat panggilan recv_into sebanyak yang diperlukan sampai menyediakan cukup data. Itu mungkin sesedikit nol (jika sudah ada cukup data dalam buffer) atau sebanyak persis jumlah byte yang Anda terima jika rekan jarak jauh memberi Anda tetesan-tetesan satu byte pada satu waktu. Sebenarnya sangat sedikit yang dapat kita lakukan tentang itu: karena sifat dari panggilan read() terhadap objek yang disangga seperti itu, kita bahkan tidak mendapatkan aliran kontrol kembali di antara setiap panggilan recv_into .

Itu berarti bahwa _only_ cara untuk menjamin bahwa Anda mendapatkan tidak lebih dari n-detik menunggu adalah dengan melakukan iter_content dengan ukuran potongan 1 . Itu cara yang sangat tidak efisien untuk mengunduh file (menghabiskan terlalu banyak waktu dalam kode Python), tetapi itu adalah satu-satunya cara untuk mendapatkan jaminan yang Anda inginkan.

  1. Saya juga percaya jawabannya adalah tidak. Saat ini kami tidak memiliki gagasan tentang batas waktu _send_. Cara mendapatkannya adalah dengan menggunakan socket.setdefaulttimeout .
  2. Batas waktu baca hanya berlaku untuk pembacaan, jadi tidak masalah bagaimana Anda melewati isi.
  3. Batas waktu baca tersebut mengalami masalah yang sama dengan kasus iter_content : jika Anda memiliki permintaan untuk mengunduh semuanya, maka kami akan mengeluarkan panggilan recv_into sebanyak yang diperlukan untuk mengunduh isi, dan batas waktu berlaku kepada masing-masing secara bergantian.

Anda menabrak masalah inti di sini: permintaan tidak cukup dekat dengan soket untuk mencapai apa yang Anda cari. Kami _could_ menambahkan batas waktu pengiriman: itu adalah permintaan fitur yang berfungsi mengingat, dan itu tidak mengalami masalah yang sama seperti batas waktu baca, tetapi untuk semua yang lain kami macet karena httplib bersikeras (dengan benar) untuk bertukar ke representasi soket buffer, dan kemudian httplib sisanya menggunakan representasi buffer tersebut.

@Lukasa

Ah, betapa kacaunya, haha. Saya pikir itu mungkin terjadi tetapi saya benar-benar berharap saya salah.

Pertama, kami sangat membutuhkan batas waktu pengiriman. Saya tidak dapat memberi tahu pengguna saya bahwa unggahan mereka dapat menggantung tanpa batas dan kami tidak memiliki rencana untuk memperbaiki masalah tersebut. :/

Sepertinya aku berada dalam situasi yang mustahil saat ini. Tidak ada dukungan perpustakaan untuk batas waktu total (yang saya mengerti). Tidak ada jaminan tentang bagaimana batas waktu yang ada bekerja dengan berbagai ukuran potongan -- jika ada, saya bisa menyimpulkan waktunya: connect timeout + read timeout * chunk size. Mampu menginterupsi aliran dengan mode aliran dan generator itu bagus, tetapi karena saya tidak punya solusi untuk benar-benar membatalkan utas dengan cara lintas platform, ini juga tidak membantu. Apakah Anda melihat opsi lain untuk maju? Apa yang dilakukan pengguna lain untuk menyelesaikan masalah ini?

Pertama, kami sangat membutuhkan batas waktu pengiriman. Saya tidak dapat memberi tahu pengguna saya bahwa unggahan mereka dapat menggantung tanpa batas dan kami tidak memiliki rencana untuk memperbaiki masalah tersebut. :/

Jadi logika batas waktu yang digunakan dalam permintaan pada dasarnya adalah urllib3, jadi itu harus cukup untuk membuat perubahan di sana: jangan ragu untuk membuka permintaan fitur dan kami dapat membantu Anda melalui perubahan tersebut. Dan dalam jangka pendek, jangan ragu untuk menyelidiki menggunakan setdefaulttimeout .

Apakah Anda melihat opsi lain untuk maju? Apa yang dilakukan pengguna lain untuk menyelesaikan masalah ini?

Opsi yang Anda miliki di sini bergantung pada batasan spesifik Anda.

Jika Anda _harus_ memiliki batas waktu determinstik (yaitu, jika Anda dapat menjamin bahwa permintaan tidak akan memakan waktu lebih dari _n_ detik) maka Anda tidak dapat dengan mudah melakukannya dengan pustaka standar Python seperti yang ada saat ini. Di Python 2.7 Anda harus menambal socket._fileobject untuk memungkinkan Anda menjalankan batas waktu berurutan untuk setiap panggilan recv , tetapi di Python 3 itu bahkan lebih sulit karena Anda perlu menambal ke kelas yang implementasinya ada di C ( io.BufferedReader ), yang akan menjadi mimpi buruk.

Jika tidak, satu-satunya cara Anda mendapatkannya adalah dengan mengaktifkan _off_ buffering di perpustakaan standar. Itu akan merusak httplib dan semua tambalan kami di atasnya, yang mengasumsikan bahwa kami dapat membuat panggilan read(x) yang akan berperilaku tidak seperti syscall read pada soket tetapi seperti read syscall pada file (yaitu, mengembalikan panjang deterministik).

Dengan kata lain: jika Anda _memerlukan_ batas waktu deterministik, Anda akan menemukan bahwa sejumlah besar perpustakaan tidak dapat menyediakannya untuk Anda. Pada dasarnya, jika mereka menggunakan httplib atau socket.makefile maka Anda akan kurang beruntung: tidak ada cara bersih untuk menjamin bahwa kontrol kembali kepada Anda dalam waktu yang ditentukan kecuali berulang kali mengeluarkan panjang -1 membaca. Anda _dapat_ melakukan itu, tetapi itu akan merusak kinerja Anda.

Jadi Anda memiliki tradeoff di sini: jika Anda menginginkan batas waktu deterministik, cara buffering diimplementasikan di pustaka standar Python (dan karenanya, dalam permintaan) tidak akan membuatnya tersedia untuk Anda. Anda bisa mendapatkannya kembali dengan menonaktifkan buffering dan menulis ulang kode, tetapi itu berpotensi sangat merugikan kinerja Anda kecuali jika Anda mengimplementasikan kembali buffering dengan cara yang mengakui batas waktu.

Anda dapat mengimplementasikan kode yang diperlukan di pustaka standar Python di kelas BufferedReader : Anda pasti dapat bertanya kepada orang-orang Python apakah mereka tertarik. Tapi aku tidak akan menahan napas.

Jadi logika batas waktu yang digunakan dalam permintaan pada dasarnya adalah urllib3, jadi itu harus cukup untuk membuat perubahan di sana: jangan ragu untuk membuka permintaan fitur dan kami dapat membantu Anda melalui perubahan tersebut. Dan dalam jangka pendek, jangan ragu untuk menyelidiki menggunakan setdefaulttimeout.

Permintaan fitur di urllib3 atau di sini? Akan membuka satu (atau keduanya) secepatnya.

Permintaan fitur di urllib3: kami tidak perlu mengekspos sesuatu yang baru dalam permintaan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat