https://github.com/alex/http-client-bench berisi tolok ukur yang saya gunakan.
Hasilnya adalah seperti:
| | permintaan/http | soket |
| --- | --- | --- |
| CPython | 12MB/dtk | 200MB/dtk |
| PyPy | 80MB/dtk | 300MB/dtk |
| Pergi | 150MB/dtk | t/a |
permintaan membebankan overhead yang cukup besar dibandingkan dengan soket, terutama pada CPython.
Overhead itu secara tak terduga besar. Namun, menghindarinya mungkin sulit.
Masalah besarnya adalah kita melakukan cukup banyak pemrosesan per chunk. Itu semua jalan ke bawah tumpukan: permintaan, urllib3 dan httplib. Akan sangat menarik untuk melihat di mana waktu yang dihabiskan untuk mencari tahu siapa yang menyebabkan inefisiensi.
tebak langkah selanjutnya adalah mencoba membuat profil httplib / urllib3 untuk melihat
kinerja di sana?
Kevin Burke
telepon: 925.271.7005 | dua puluhmilidetik.com
Pada Kam, 4 Des 2014 jam 17:01, Cory Benfield [email protected]
menulis:
Overhead itu secara tak terduga besar. Namun, menghindarinya mungkin sulit.
Masalah besarnya adalah kita melakukan cukup banyak pemrosesan per chunk. itu
sepanjang tumpukan: permintaan, urllib3 dan httplib. Itu akan
sangat menarik untuk melihat di mana waktu yang dihabiskan untuk mencari tahu siapa
menyebabkan inefisiensi.—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65732050
.
Baru saja menjalankan benchmark dengan urllib3:
PyPy: 120MB/dtk
CPython: 70MB/dtk
Dan saya menjalankan ulang permintaan CPython +: 35MB/dtk
(Mesin saya tampaknya mengalami sedikit kebisingan di tolok ukur, jika ada yang memiliki sistem yang lebih tenang, mereka dapat mengaktifkannya, itu akan luar biasa)
Saya mencoba menjalankan ini di mesin saya setelah mematikan satu sama lain
jendela aplikasi & terminal dan mendapatkan cukup banyak kebisingan juga - the
benchmark socket berkisar antara 30mb/s hingga 460mb/s.
Kevin Burke
telepon: 925.271.7005 | dua puluhmilidetik.com
Pada Thu, 4 Desember 2014 pada 9:24 PM, Alex Gaynor [email protected]
menulis:
Baru saja menjalankan benchmark dengan urllib3:
PyPy: 120MB/dtk
CPython: 70MB/dtkDan saya menjalankan ulang permintaan CPython +: 35MB/dtk
(Mesin saya tampaknya mengalami sedikit noise di benchmark, jika
siapa pun memiliki sistem yang lebih tenang, mereka dapat mengaktifkannya, itu akan luar biasa)—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65748982
.
Saya membuat tolok ukur lebih mudah dijalankan sekarang, sehingga orang lain mudah-mudahan dapat memverifikasi nomor saya:
CPython:
BENCH SOCKET:
8GiB 0:00:22 [ 360MiB/s] [======================================================>] 100%
BENCH HTTPLIB:
8GiB 0:02:34 [53.1MiB/s] [======================================================>] 100%
BENCH URLLIB3:
8GiB 0:01:30 [90.2MiB/s] [======================================================>] 100%
BENCH REQUESTS
8GiB 0:01:30 [90.7MiB/s] [======================================================>] 100%
BENCH GO HTTP
8GiB 0:00:26 [ 305MiB/s] [======================================================>] 100%
PyPy:
BENCH SOCKET:
8GiB 0:00:22 [ 357MiB/s] [======================================================>] 100%
BENCH HTTPLIB:
8GiB 0:00:43 [ 189MiB/s] [======================================================>] 100%
BENCH URLLIB3:
8GiB 0:01:07 [ 121MiB/s] [======================================================>] 100%
BENCH REQUESTS
8GiB 0:01:09 [ 117MiB/s] [======================================================>] 100%
BENCH GO HTTP
8GiB 0:00:26 [ 307MiB/s] [======================================================>] 100%
Uh...angka-angka itu aneh. httplib CPython lebih lambat dari permintaan atau urllib3, meskipun kedua perpustakaan menggunakan httplib? Itu tidak mungkin benar.
Mereka mereproduksi secara konsisten untuk saya -- dapatkah Anda mencoba tolok ukur dan melihat apakah
Anda dapat mereproduksi? Dengan asumsi Anda bisa, apakah Anda melihat ada yang salah dengan
tolak ukur?
Pada Jum, 05 Des 2014 pukul 11:16:45 Cory Benfield [email protected]
menulis:
Uh...angka-angka itu aneh. httplib CPython lebih lambat dari permintaan atau
urllib3, meskipun kedua perpustakaan menggunakan httplib? Itu tidak mungkin benar.—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65821989
.
Saya baru saja mengambil mesin yang dikenal senyap sekarang. Perlu beberapa menit untuk tersedia karena ini adalah kotak fisik yang harus diinstal (Tuhan, saya suka MAAS).
CPython 2.7.8
BENCH SOCKET:
8GiB 0:00:26 [ 309MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:02:24 [56.5MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:01:42 [79.7MiB/s] [================================>] 100%
BENCH REQUESTS
8GiB 0:01:45 [77.9MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:27 [ 297MiB/s] [================================>] 100%
Untuk apa nilainya:
Tambalan ini , CPython 3.4.2
:
BENCH SOCKET:
8GiB 0:00:27 [ 302MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:00:53 [ 151MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:00:54 [ 149MiB/s] [================================>] 100%
BENCH REQUESTS
8GiB 0:00:56 [ 144MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:31 [ 256MiB/s] [================================>] 100%
Anda seharusnya bisa mendapatkan efek yang sama pada Python2 dengan
env PYTHONUNBUFFERED=
atau -u
bendera.
Pada Jumat, 05 Des 2014 pukul 11:42:36 Corey Farwell [email protected]
menulis:
Untuk apa nilainya:
Tambalan ini https://Gist.github.com/frewsxcv/1c0f3c81cda508e1bca9 , CPython
3.4.2:SOKET BENCH:
8GiB 0:00:27 [ 302MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:00:53 [ 151MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:00:54 [ 149MiB/s] [================================>] 100%
PERMINTAAN BANGKU
8GiB 0:00:56 [ 144MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:31 [ 256MiB/s] [================================>] 100%—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65826239
.
@alex Menariknya, baik env PYTHONUNBUFFERED=
atau -u
memiliki efek yang sama pada Python 2. Hasil dari mesin saya masuk.
Baiklah, data di bawah ini berasal dari mesin yang tidak melakukan apa pun selain menjalankan tes ini. Tes terakhir dijalankan dengan set flag Python -u
, dan seperti yang Anda lihat, flag itu tidak berpengaruh.
Python 2.7.6
go version go1.2.1 linux/amd64
BENCH SOCKET:
8GiB 0:00:16 [ 500MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:01:32 [88.6MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
BENCH REQUESTS
8GiB 0:01:21 [ 100MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:21 [ 385MiB/s] [================================>] 100%
Python 2.7.6
go version go1.2.1 linux/amd64
BENCH SOCKET:
8GiB 0:00:16 [ 503MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:01:33 [87.8MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
BENCH REQUESTS
8GiB 0:01:22 [99.3MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:20 [ 391MiB/s] [================================>] 100%
Python 2.7.6
go version go1.2.1 linux/amd64
BENCH SOCKET:
8GiB 0:00:16 [ 506MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:01:31 [89.1MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
BENCH REQUESTS
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:21 [ 389MiB/s] [================================>] 100%
Angka-angka ini sangat stabil, dan menunjukkan fitur-fitur berikut:
FWIW, saya baru saja menggabungkan menambahkan buffering=True
dari @kevinburke , lakukan langkah Anda
termasuk itu?
Pada Jumat, 05 Des 2014 pukul 12:04:40 PM Cory Benfield [email protected]
menulis:
Baiklah, data di bawah ini berasal dari mesin yang tidak melakukan hal lain
tetapi menjalankan tes ini. Tes terakhir dijalankan dengan flag Python -u
set, dan seperti yang Anda lihat, bendera itu tidak berpengaruh.Python 2.7.6
go versi go1.2.1 linux/amd64
SOKET BENCH:
8GiB 0:00:16 [ 500MiB/s] [==============================>] 100%
BENCH HTTPLIB:
8GiB 0:01:32 [88.6MiB/s] [==============================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
PERMINTAAN BANGKU
8GiB 0:01:21 [ 100MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:21 [ 385MiB/s] [==============================>] 100%Python 2.7.6
go versi go1.2.1 linux/amd64
SOKET BENCH:
8GiB 0:00:16 [ 503MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:01:33 [87.8MiB/s] [==============================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [==============================>] 100%
PERMINTAAN BANGKU
8GiB 0:01:22 [99,3MiB/s] [==============================>] 100%
BENCH GO HTTP
8GiB 0:00:20 [ 391MiB/s] [================================>] 100%Python 2.7.6
go versi go1.2.1 linux/amd64
SOKET BENCH:
8GiB 0:00:16 [ 506MiB/s] [==============================>] 100%
BENCH HTTPLIB:
8GiB 0:01:31 [89.1MiB/s] [==============================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
PERMINTAAN BANGKU
8GiB 0:01:20 [ 101MiB/s] [==============================>] 100%
BENCH GO HTTP
8GiB 0:00:21 [ 389MiB/s] [==============================>] 100%Angka-angka ini sangat stabil, dan menunjukkan fitur-fitur berikut:
- Pembacaan soket mentah cepat (duh).
- Go adalah sekitar 80% kecepatan membaca soket mentah.
- urllib3 adalah sekitar 20% kecepatan membaca soket mentah.
- permintaan sedikit lebih lambat dari urllib3, yang masuk akal karena kami
tambahkan beberapa bingkai tumpukan untuk dilewati data.- httplib lebih lambat dari request/urllib3. Itu tidak mungkin,
dan saya menduga bahwa kita harus mengonfigurasi httplib atau perpustakaan soket di
cara yang httplib tidak.—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65829335
.
Cory - lihat versi terbaru dari klien bangku yang menyalakan
buffering=True di httplib (seperti yang dilakukan permintaan/urllib3)
Kevin Burke
telepon: 925.271.7005 | dua puluhmilidetik.com
Pada Jum, 5 Des 2014 jam 10:04, Cory Benfield [email protected]
menulis:
Baiklah, data di bawah ini berasal dari mesin yang tidak melakukan hal lain
tetapi menjalankan tes ini. Tes terakhir dijalankan dengan flag Python -u
set, dan seperti yang Anda lihat, bendera itu tidak berpengaruh.Python 2.7.6
go versi go1.2.1 linux/amd64
SOKET BENCH:
8GiB 0:00:16 [ 500MiB/s] [==============================>] 100%
BENCH HTTPLIB:
8GiB 0:01:32 [88.6MiB/s] [==============================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [==============================>] 100%
PERMINTAAN BANGKU
8GiB 0:01:21 [ 100MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:21 [ 385MiB/s] [==============================>] 100%Python 2.7.6
go versi go1.2.1 linux/amd64
SOKET BENCH:
8GiB 0:00:16 [ 503MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:01:33 [87.8MiB/s] [==============================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [==============================>] 100%
PERMINTAAN BANGKU
8GiB 0:01:22 [99,3MiB/s] [==============================>] 100%
BENCH GO HTTP
8GiB 0:00:20 [ 391MiB/s] [================================>] 100%Python 2.7.6
go versi go1.2.1 linux/amd64
SOKET BENCH:
8GiB 0:00:16 [ 506MiB/s] [==============================>] 100%
BENCH HTTPLIB:
8GiB 0:01:31 [89.1MiB/s] [==============================>] 100%
BENCH URLLIB3:
8GiB 0:01:20 [ 101MiB/s] [==============================>] 100%
PERMINTAAN BANGKU
8GiB 0:01:20 [ 101MiB/s] [==============================>] 100%
BENCH GO HTTP
8GiB 0:00:21 [ 389MiB/s] [==============================>] 100%Angka-angka ini sangat stabil, dan menunjukkan fitur-fitur berikut:
- Pembacaan soket mentah cepat (duh).
- Go adalah sekitar 80% kecepatan membaca soket mentah.
- urllib3 adalah sekitar 20% kecepatan membaca soket mentah.
- permintaan sedikit lebih lambat dari urllib3, yang masuk akal karena kami
tambahkan beberapa bingkai tumpukan untuk dilewati data.- httplib lebih lambat dari request/urllib3. Itu tidak mungkin,
dan saya menduga bahwa kita harus mengonfigurasi httplib atau perpustakaan soket di
cara yang httplib tidak.—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65829335
.
Ya, itu memperbaiki perilaku kinerja httplib agar jauh lebih masuk akal.
Hasil dan kesimpulan baru:
Python 2.7.6
go version go1.2.1 linux/amd64
BENCH SOCKET:
8GiB 0:00:16 [ 499MiB/s] [================================>] 100%
BENCH HTTPLIB:
8GiB 0:01:12 [ 113MiB/s] [================================>] 100%
BENCH URLLIB3:
8GiB 0:01:21 [ 100MiB/s] [================================>] 100%
BENCH REQUESTS
8GiB 0:01:20 [ 101MiB/s] [================================>] 100%
BENCH GO HTTP
8GiB 0:00:20 [ 391MiB/s] [================================>] 100%
Jadi, bisa dibilang biaya sebenarnya di sini adalah httplib. Mempercepat ini membutuhkan httplib menyingkir.
Saya tertarik untuk mengetahui bagian mana dari httplib yang membebani kami. Saya pikir membuat profil bench_httplib.py
adalah langkah selanjutnya yang baik.
Saya telah mengesampingkan konversi soket ke objek file melalui socket.makefile
dengan menambahkan baris itu ke pengujian bench_socket.py
, yang tidak memperlambatnya sama sekali. Anehnya, tampaknya membuatnya lebih cepat.
Jawabannya hampir pasti adalah transfer-encoding: penanganan chunked.
Lihat: https://github.com/alex/http-client-bench/pull/6 , beralih ke
Content-Length di server menghasilkan beberapa hasil yang tidak terduga.
Pada Jumat, 05 Des 2014 pukul 12:24:53 PM Cory Benfield [email protected]
menulis:
Jadi, bisa dibilang biaya sebenarnya di sini adalah httplib. Mempercepat ini membutuhkan
mendapatkan httplib keluar dari jalan.Saya tertarik untuk mengetahui bagian mana dari httplib yang membebani kami. Saya
berpikir membuat profil bench_httplib.py adalah langkah selanjutnya yang baik.—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65831653
.
Menarik.
Penanganan chunked hampir pasti masalahnya, dan saya tidak terlalu terkejut bahwa go menanganinya dengan lebih baik, terutama karena chunked adalah mode HTTP default untuk go.
Namun, permintaan yang lebih cepat daripada soket mentah ... tidak terduga!
Satu hal yang perlu diperhatikan: jika soket tidak mendekode pengkodean chunked pada pengujian sebelumnya, maka itu mendapat keuntungan yang tidak adil, karena sebenarnya membaca lebih sedikit data daripada metode lainnya! Mereka semua membaca header chunked serta data 8GB.
Ini mengarah ke pertanyaan lanjutan: apakah kita masih berpikir semua metode ini benar-benar membaca jumlah data yang sama?
Ya, lapisan soket curang, tidak memecahkan kode metadata yang dipotong,
dan secara teknis membaca sedikit lebih sedikit. Itu ada di sana sebagai garis dasar untuk "seberapa cepat
bisa kita baca", bukan untuk membuktikan apa-apa.
Pada Jum, 05 Des 2014 pukul 12:33:10 PM Cory Benfield [email protected]
menulis:
Menarik.
Penanganan yang terpotong hampir pasti masalahnya, dan saya tidak benar-benar
terkejut bahwa go menanganinya dengan lebih baik, terutama karena chunked adalah defaultnya
Modus HTTP untuk pergi.Namun, permintaan yang lebih cepat daripada soket mentah ... tidak terduga!
Satu hal yang perlu diperhatikan: jika soket tidak mendekode pengkodean chunked
dalam tes sebelumnya maka itu mendapat keuntungan yang tidak adil, seperti yang sebenarnya
membaca lebih sedikit data daripada metode lainnya! Mereka semua sedang membaca
header chunked serta 8GB data.Ini mengarah pada pertanyaan lanjutan: apakah kita masih memikirkan semua metode ini?
benar-benar membaca jumlah data yang sama?—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -65833299
.
Saya tidak akan terkejut jika ini terkait dengan ukuran potongan yang kita baca dari soket pada suatu waktu.
Kue untuk @alex karena sangat membantu :kue:
@nelhage melakukan beberapa penelusuran dari berbagai contoh (dalam transfer
penyandian: kasus terpotong) https://Gist.github.com/nelhage/dd6490fbc5cfb815f762
adalah hasilnya. Sepertinya ada bug di httplib yang menyebabkannya
tidak selalu membaca sepotong penuh dari soket.
Pada Senin 8 Desember 2014 di 9:05:14 Kenneth Reitz [email protected]
menulis:
Kue untuk @alex https://github.com/alex karena sangat membantu [gambar:
:kue:]—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -66147998
.
Jadi apa yang kita miliki di sini adalah bug di perpustakaan standar yang tidak ada yang benar-benar memelihara? ( @Lukasa memiliki setidaknya 2 set tambalan yang telah dibuka selama> 1 tahun.) Mungkin saya akan menaikkan bau pada daftar di suatu tempat malam ini
Seseorang (mungkin saya mengerti, tidak jelas) mungkin perlu menelusuri dengan pdb
atau sesuatu dan cari tahu kode persis apa yang menghasilkan 20-byte itu
dibaca sehingga kami dapat menyusun laporan bug yang baik.
Pada Senin 08 Des 2014 pukul 09:14:09 Ian Cordasco [email protected]
menulis:
Jadi apa yang kita miliki di sini adalah bug di perpustakaan standar yang tidak ada yang benar-benar
memelihara? ( @Lukasa https://github.com/Lukasa memiliki setidaknya 2 tambalan
set yang telah dibuka selama> 1 tahun.) Mungkin saya akan menaikkan bau pada daftar
di suatu tempat malam ini—
Balas email ini secara langsung atau lihat di GitHub
https://github.com/kennethreitz/requests/issues/2371#issuecomment -66149522
.
Saya akan mencoba memasukkannya malam ini atau besok jika tidak ada orang lain yang melakukannya.
Jadi, ada berita tentang akar masalahnya? Apa yang menghasilkan bacaan singkat ini, dan seberapa banyak situasi membaik tanpanya?
@kislyuk Tidak sejauh yang saya ketahui. Mudah-mudahan saya punya waktu untuk mengejarnya di liburan natal ini.
Terima kasih @Lukas. Saya berurusan dengan masalah kinerja di mana kecepatan unduhan pada respons chunked menggunakan urllib3/requests jauh lebih lambat daripada dengan curl dan perpustakaan lain, dan mencoba memahami apakah ini penyebabnya.
Saya mengaduk-aduk dengan ini sedikit. Bacaan singkat berasal dari fungsi _read_chunked di httplib
https://fossies.org/linux/misc/Python-2.7.9.tgz/Python-2.7.9/Lib/httplib.py#l_585
Pembacaan 2 byte tampaknya terutama dari baris 622.
Saya mendapat pola strace yang sedikit berbeda dengan yang diposting sebelumnya:
recvfrom(3, "400\r\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0"..., 8192, 0, NULL, NULL) = 8192
recvfrom(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 0\0\0\0\0\0\0\0\0\0"..., 54, 0, NULL, NULL) = 54
recvfrom(3, "\r\n", 2, 0, NULL, NULL) = 2
Pola ini dapat dijelaskan sebagai berikut:
Pola kemudian akan berulang (kembali ke langkah 1)
FWIW, saya menemukan bahwa kecepatan sederhana (20% atau lebih) dapat dilakukan di sini dengan menggulirkan terminator potongan 2 byte yang dibaca ke dalam bacaan badan potongan, yaitu daripada ini:
value.append(self._safe_read(chunk_left))
amt -= chunk_left
self._safe_read(2) # toss the CRLF at the end of the chunk
lakukan ini sebagai gantinya:
value.append(self._safe_read(chunk_left + 2)[:-2])
amt -= chunk_left
Sungguh, meskipun, mungkin akan lebih baik jika pembacaan untuk 54 byte dapat menyangga lebih banyak byte daripada 54 (yaitu 8192 byte) yang berarti soket yang disangga tidak akan kosong ketika menyangkut pembacaan 2 byte.
Lebih jauh dari ini. Saya tidak yakin bacaan kecil adalah faktor utama hilangnya throughput (atau tidak di localhost). Saya bermain-main dengan ukuran buffer soket sehingga itu adalah kelipatan 1031 byte dan meskipun strace tidak lagi memiliki bacaan kecil, itu tidak berdampak banyak pada throughput.
Saya pikir hilangnya throughput mungkin lebih berkaitan dengan bagaimana socket.py menangani pembacaan kecil. Berikut adalah kode yang relevan (dari socket.read):
https://fossies.org/linux/misc/Python-2.7.9.tgz/Python-2.7.9/Lib/socket.py#l_336
Ketika Anda memasukkan panjang eksplisit ke socket.read dan itu dapat dipenuhi dari data buffer yang ada maka ini adalah jalur kode:
buf = self._rbuf
buf.seek(0, 2) # seek end
#.....
# Read until size bytes or EOF seen, whichever comes first
buf_len = buf.tell()
if buf_len >= size:
# Already have size bytes in our buffer? Extract and return.
buf.seek(0)
rv = buf.read(size)
self._rbuf = StringIO()
self._rbuf.write(buf.read())
return rv
Masalah yang saya rasakan di sini adalah bahwa bahkan pembacaan 2 byte berarti menyalin sisa yang belum dibaca ke StringIO baru. Ini sepertinya akan menjadi sangat mahal untuk banyak bacaan kecil. Jika StringIO yang diberikan entah bagaimana dapat terkuras pada setiap pembacaan daripada pola saat ini menyalin sisa yang belum dibaca ke StringIO baru maka saya berharap itu dapat membantu throughput
@gardenia Saya belum sempat menyerap semua ini, tapi terima kasih banyak atas usaha dan kerja keras Anda di sini. @shazow mungkin Anda akan menemukan penelitian @gardenia menarik.
:+1: terima kasih @gardenia. Kebetulan, penelitian saya sendiri tentang kinerja dalam kasus penggunaan saya menemukan bahwa dalam kasus saya tanggapannya tidak dipotong, tetapi urllib3 berkinerja 20+% lebih cepat daripada permintaan, jadi ada beberapa overhead yang diperkenalkan yang ingin saya cirikan. Masih sesuai dengan judul masalah ini, tetapi akar masalahnya berbeda.
Menarik, terima kasih telah berbagi! :)
Sepertinya tujuan yang bagus untuk ditangani oleh Hyper
@alex - Saya bermain-main sedikit dengan urllib3 vs permintaan masalah kinerja non-potong yang Anda sebutkan. Saya rasa saya melihat penurunan permintaan serupa sebesar 20%.
Dalam permintaan saya secara spekulatif mencoba mengganti panggilan ke self.raw.stream dengan implementasi inline stream() (dari urllib3). Tampaknya membawa throughput lebih dekat antara permintaan dan urllib3, setidaknya di mesin saya:
--- requests.repo/requests/models.py 2015-03-06 16:05:52.072509869 +0000
+++ requests/models.py 2015-03-07 20:49:25.618007438 +0000
@@ -19,6 +19,7 @@
from .packages.urllib3.fields import RequestField
from .packages.urllib3.filepost import encode_multipart_formdata
from .packages.urllib3.util import parse_url
+from .packages.urllib3.util.response import is_fp_closed
from .packages.urllib3.exceptions import (
DecodeError, ReadTimeoutError, ProtocolError, LocationParseError)
from .exceptions import (
@@ -652,8 +654,12 @@
try:
# Special case for urllib3.
try:
- for chunk in self.raw.stream(chunk_size, decode_content=True):
- yield chunk
+ while not is_fp_closed(self.raw._fp):
+ data = self.read(amt=chunk_size, decode_content=True)
+
+ if data:
+ yield data
+
except ProtocolError as e:
raise ChunkedEncodingError(e)
except DecodeError as e:
Mungkin Anda bisa mencoba hal yang sama pada mesin Anda untuk melihat apakah itu membuat perbedaan bagi Anda juga.
(Catatan ya saya tahu panggilan ke is_fp_closed adalah penghilang enkapsulasi, itu tidak dimaksudkan sebagai tambalan serius hanya titik data)
@shazow Harapan saya bahwa BufferedSocket
yang digunakan hyper harus mengatasi banyak inefisiensi itu, dengan pada dasarnya mencegah pembacaan kecil. Saya ingin tahu apakah httplib
pada Py3 memiliki masalah ini, karena ia menggunakan io.BufferedReader
secara ekstensif, yang seharusnya memberikan manfaat yang kira-kira sama dengan BufferedSocket
.
Akan tetapi, tentu saja, ketika hyper
menumbuhkan fungsionalitas HTTP/1.1 yang cukup untuk berguna, kita harus mencoba membandingkannya bersama implementasi lain ini dan melakukan upaya untuk membuat hyper
secepat mungkin.
Tidak aktif selama hampir satu tahun. Penutupan.
Saya melihat masalah serupa, throughput 10x lebih sedikit menggunakan requests
dibandingkan dengan urllib3
.
Saya pikir masalahnya ada di dalam kelas HTTPResponse
urllib3, ketika dibaca sebagai iterator, throughputnya benar-benar buruk. Saya membuat kode saya berfungsi dengan peretasan yang sangat buruk: Saya mengembalikan objek httplib.HTTPResponse
digarisbawahi yang digunakan oleh urllib3 dan itu tampaknya memperbaiki masalah throughput saya.
Fakta menarik: superclass HTTPResponse
urllib3 adalah io.IOBase
. Superclass httplib.HTTPResponse
Python3 adalah io.BufferedIOBase
. Aku ingin tahu apakah ada hubungannya dengan ini.