Kesiapan vs. Selesainya Penggunaan Memori Iyn Async?

12

Saya menonton pembicaraan tentang penerapan Async IO di Rust dan Carl ini menyebutkan dua model potensial. Kesiapan dan Kelengkapan.

Model Kesiapan:

  • Anda memberi tahu kernel yang ingin Anda baca dari soket
  • lakukan hal-hal lain untuk sementara ...
  • kernel memberi tahu Anda ketika soket siap
  • Anda membaca (mengisi buffer)
  • lakukan apapun yang kamu butuhkan
  • bebaskan buffer (terjadi secara otomatis dengan Rust)

Model Penyelesaian:

  • Anda mengalokasikan buffer untuk diisi kernel
  • lakukan hal-hal lain untuk sementara ...
  • kernel memberi tahu Anda ketika buffer telah terisi
  • lakukan apa pun yang Anda perlukan dengan data
  • bebaskan buffer

Dalam contoh Carl tentang menggunakan model kesiapan Anda dapat beralih dari soket yang siap mengisi dan membebaskan buffer global yang membuatnya tampak seperti itu akan menggunakan memori jauh lebih sedikit.

Sekarang asumsi saya:

Di bawah kap (dalam ruang kernel) ketika soket dikatakan "siap", data sudah ada. Ini telah masuk ke soket melalui jaringan (atau dari mana saja) dan OS memegang data.

Bukannya alokasi memori itu secara ajaib tidak terjadi dalam model kesiapan. Hanya saja OS itu mengambil abstraksi dari Anda. Dalam model Penyelesaian, OS meminta Anda untuk mengalokasikan memori sebelum data benar-benar masuk dan jelas apa yang terjadi.

Inilah versi saya dari Model Kesiapan:

  • Anda memberi tahu kernel yang ingin Anda baca dari soket
  • lakukan hal-hal lain untuk sementara ...
  • PERUBAHAN: data masuk ke OS (suatu tempat di memori kernel)
  • kernel memberi tahu Anda bahwa soketnya sudah siap
  • Anda membaca (isi buffer lain secara terpisah dari buffer kernel abover (atau Anda mendapatkan pointer ke sana?))
  • lakukan apapun yang kamu butuhkan
  • bebaskan buffer (terjadi secara otomatis dengan Rust)

/ Asumsi saya

Saya kebetulan suka menjaga program pengguna-ruang kecil tapi saya hanya ingin beberapa klarifikasi tentang apa yang, pada kenyataannya, terjadi di sini. Saya tidak melihat bahwa satu model secara inheren akan menggunakan lebih sedikit memori atau mendukung tingkat IO bersamaan yang lebih tinggi. Saya ingin mendengar pemikiran dan penjelasan yang lebih dalam tentang ini.

kjs3
sumber
Saya juga tiba di sini dari pembicaraan di YouTube itu. Bagi siapa pun yang belajar tentang bagaimana async IO atau bagaimana menerapkan loop acara, tim Rust memiliki daftar putar "Wawancara Aysnc" di sini mewawancarai orang-orang yang sangat berpengetahuan dari komunitas
cacoder

Jawaban:

5

Dalam Model Kesiapan, konsumsi memori sebanding dengan jumlah data yang tidak dikonsumsi oleh aplikasi.

Dalam Model Penyelesaian konsumsi memori sebanding dengan jumlah panggilan soket yang beredar.

Jika ada banyak soket yang sebagian besar tidak digunakan maka Model Kesiapan mengkonsumsi lebih sedikit memori.

Ada perbaikan yang mudah untuk Model Penyelesaian: Lakukan pembacaan 1 byte. Ini hanya mengkonsumsi buffer kecil. Ketika membaca selesai masalah lain (mungkin sinkron) membaca yang mendapatkan sisa data.

Dalam beberapa bahasa, Model Penyelesaian sangat mudah diterapkan. Saya menganggapnya sebagai pilihan default yang baik.

usr
sumber
1

Dalam model Penyelesaian, OS meminta Anda untuk mengalokasikan memori sebelum data benar-benar masuk dan jelas apa yang terjadi.

Tetapi apa yang terjadi jika lebih banyak data masuk daripada yang Anda alokasikan untuk ruang? Kernel masih harus mengalokasikan buffernya sendiri agar tidak menjatuhkan data. (Misalnya, inilah sebabnya trik baca 1 byte yang disebutkan dalam jawaban usr berfungsi.)

Imbalannya adalah bahwa sementara Model Penyelesaian mengkonsumsi lebih banyak memori, itu juga (kadang-kadang) dapat melakukan lebih sedikit operasi penyalinan, karena menjaga buffer sekitar berarti perangkat keras dapat DMA langsung keluar dari atau ke dalamnya. Saya juga curiga (tetapi kurang yakin) bahwa Model Penyelesaian cenderung melakukan operasi penyalinan yang sebenarnya (bila ada) di utas lain, setidaknya untuk IOCP Windows, sedangkan Model Kesiapan melakukannya sebagai bagian dari non-pemblokiran read()atau write()panggilan.

rpjohnst
sumber