<p>permintaan memiliki kinerja buruk mengalirkan respons biner besar</p>

Dibuat pada 5 Des 2014  ·  40Komentar  ·  Sumber: psf/requests

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.

Propose Close

Semua 40 komentar

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/dtk

Dan 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:

  1. Pembacaan soket mentah cepat (duh).
  2. Go adalah sekitar 80% kecepatan membaca soket mentah.
  3. urllib3 adalah sekitar 20% kecepatan membaca soket mentah.
  4. permintaan sedikit lebih lambat dari urllib3, yang masuk akal karena kami menambahkan beberapa bingkai tumpukan untuk dilewati data.
  5. httplib lebih lambat dari request/urllib3. Itu tidak mungkin, dan saya menduga bahwa kita harus mengonfigurasi httplib atau pustaka soket dengan cara yang tidak dilakukan httplib.

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:

  1. Pembacaan soket mentah cepat (duh).
  2. Go adalah sekitar 80% kecepatan membaca soket mentah.
  3. urllib3 adalah sekitar 20% kecepatan membaca soket mentah.
  4. permintaan sedikit lebih lambat dari urllib3, yang masuk akal karena kami
    tambahkan beberapa bingkai tumpukan untuk dilewati data.
  5. 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:

  1. Pembacaan soket mentah cepat (duh).
  2. Go adalah sekitar 80% kecepatan membaca soket mentah.
  3. urllib3 adalah sekitar 20% kecepatan membaca soket mentah.
  4. permintaan sedikit lebih lambat dari urllib3, yang masuk akal karena kami
    tambahkan beberapa bingkai tumpukan untuk dilewati data.
  5. 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%
  1. Pembacaan soket mentah cepat (duh).
  2. Go adalah sekitar 80% kecepatan membaca soket mentah.
  3. httplib hanya di bawah 25% kecepatan baca soket mentah.
  4. urllib3 sekitar 20% kecepatan membaca soket mentah, menambahkan beberapa overhead kecil ke httplib.
  5. permintaan sedikit lebih lambat dari urllib3, yang masuk akal karena kami menambahkan beberapa bingkai tumpukan untuk dilewati data.

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:

  • self.fp.readline (baris 591) memicu pembacaan buffered untuk 8192 byte (dalam socket.readline)
  • setiap potongan yang dikonsumsi adalah 1031 byte (5 byte panjang potongan ("400\r\n") + 1024 byte data + 2 byte terminator)
  • kita dapat menggunakan 7 bongkahan seperti itu dari 8192 byte yang di-buffer sehingga menyisakan 975 byte
  • kami kemudian membaca panjang potongan berikutnya (5 byte) yang tersisa dengan 970 byte
  • kami sekarang hanya memiliki 970 byte yang tidak cukup untuk memenuhi potongan saat ini (1024) jadi kami kembali ke jaringan untuk kekurangan 54 byte
  • untuk mencapai ini httplib melakukan sock.read(54) pada byte yang luar biasa. socket.read dalam kasus ini (dengan panjang eksplisit) akan memilih untuk pergi ke jaringan untuk 54 byte yang ditentukan (daripada buffering 8192 lainnya)
  • kita kemudian membaca terminator chunk yaitu 2 byte dan lagi itu adalah skenario yang sama seperti di atas

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.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

avinassh picture avinassh  ·  4Komentar

remram44 picture remram44  ·  4Komentar

justlurking picture justlurking  ·  3Komentar

eromoe picture eromoe  ·  3Komentar

JimHokanson picture JimHokanson  ·  3Komentar