Misalkan ada dua utas, yang berkomunikasi dengan tidak sinkron mengirim pesan data satu sama lain. Setiap utas memiliki beberapa jenis antrian pesan.
Pertanyaan saya sangat rendah: Apa yang bisa diharapkan menjadi cara paling efisien untuk mengelola memori? Saya dapat memikirkan beberapa solusi:
- Pengirim membuat objek melalui
new
. Panggilan penerimadelete
. - Memory pooling (untuk mentransfer memori kembali ke pengirim)
- Pengumpulan sampah (mis., Boehm GC)
- (Jika objek cukup kecil) salin dengan nilai untuk menghindari alokasi tumpukan sepenuhnya
1) adalah solusi yang paling jelas, jadi saya akan menggunakannya untuk prototipe. Kemungkinannya sudah cukup baik. Tetapi terlepas dari masalah spesifik saya, saya bertanya-tanya teknik mana yang paling menjanjikan jika Anda mengoptimalkan kinerja.
Saya berharap pooling menjadi yang terbaik secara teoritis, terutama karena Anda dapat menggunakan pengetahuan ekstra tentang aliran informasi antara utas. Namun, saya khawatir itu juga yang paling sulit untuk dilakukan dengan benar. Banyak penyetelan ... :-(
Pengumpulan sampah harus cukup mudah untuk ditambahkan setelahnya (setelah solusi 1), dan saya berharap ini akan bekerja dengan sangat baik. Jadi, saya kira itu adalah solusi paling praktis jika 1) ternyata terlalu tidak efisien.
Jika objek kecil dan sederhana, salin berdasarkan nilai mungkin yang tercepat. Namun, saya khawatir hal itu memaksa pembatasan yang tidak perlu pada implementasi pesan yang didukung, jadi saya ingin menghindarinya.
sumber
unique_ptr
, saya kira maksud Andashared_ptr
. Tetapi sementara tidak ada keraguan bahwa menggunakan pointer pintar baik untuk manajemen sumber daya, itu tidak mengubah fakta bahwa Anda menggunakan beberapa bentuk alokasi memori dan deallokasi. Saya pikir pertanyaan ini lebih rendah.Performa terbesar yang menghantam ketika mengomunikasikan suatu objek dari satu utas ke utas lainnya adalah overhead dari meraih kunci. Ini ada di urutan beberapa mikrodetik, yang secara signifikan lebih dari waktu rata-rata sepasang
new
/delete
ambil (pada urutan seratus nanodetik).new
Implementasi yang sehat mencoba menghindari penguncian di hampir semua biaya untuk menghindari kinerja mereka yang gagal.Karena itu, Anda ingin memastikan bahwa Anda tidak perlu mengambil kunci saat mengomunikasikan objek dari satu utas ke utas lainnya. Saya tahu dua metode umum untuk mencapai ini. Keduanya hanya bekerja secara tidak langsung antara satu pengirim dan satu penerima:
Gunakan penyangga dering. Kedua proses mengontrol satu pointer ke buffer ini, satu adalah pointer baca, yang lainnya adalah pointer tulis.
Pengirim pertama memeriksa apakah ada ruang untuk menambahkan elemen dengan membandingkan pointer, lalu menambahkan elemen, lalu menambah pointer tulis.
Penerima memeriksa apakah ada elemen untuk dibaca dengan membandingkan pointer, kemudian membaca elemen, lalu menambah pointer baca.
Pointer harus berupa atom karena dibagi di antara utas. Namun, setiap pointer hanya dimodifikasi oleh satu utas, yang lain hanya perlu membaca akses ke pointer. Elemen-elemen dalam buffer mungkin adalah pointer sendiri, yang memungkinkan Anda untuk dengan mudah mengukur buffer cincin Anda ke ukuran yang tidak akan membuat blok pengirim.
Gunakan daftar tertaut yang selalu mengandung setidaknya satu elemen. Penerima memiliki pointer ke elemen pertama, pengirim memiliki pointer ke elemen terakhir. Pointer ini tidak dibagikan.
Pengirim membuat simpul baru untuk daftar tertaut, mengatur
next
penunjuknya kenullptr
. Kemudian memperbaruinext
pointer elemen terakhir untuk menunjuk ke elemen baru. Akhirnya, ia menyimpan elemen baru di penunjuknya sendiri.Penerima menonton
next
pointer elemen pertama untuk melihat apakah ada data baru yang tersedia. Jika demikian, itu menghapus elemen pertama yang lama, memajukan pointer sendiri untuk menunjuk ke elemen saat ini dan mulai memprosesnya.Dalam pengaturan ini,
next
penunjuk harus berupa atom, dan pengirim harus yakin untuk tidak melakukan dereferensi elemen terakhir kedua setelahnext
penunjuknya ditetapkan . Keuntungannya, tentu saja, bahwa pengirim tidak harus memblokir.Kedua pendekatan ini jauh lebih cepat daripada pendekatan berbasis kunci apa pun, tetapi mereka membutuhkan implementasi yang hati-hati agar benar. Dan, tentu saja, mereka memerlukan atomicity perangkat keras asli dari pointer menulis / memuat; jika
atomic<>
implementasi Anda menggunakan kunci secara internal, Anda akan sangat hancur.Demikian juga, jika Anda memiliki beberapa pembaca dan / atau penulis, Anda cukup banyak ditakdirkan: Anda dapat mencoba membuat skema tanpa kunci, tetapi akan sulit untuk mengimplementasikannya sebaik mungkin. Situasi ini lebih mudah ditangani dengan kunci. Namun, begitu Anda mengambil kunci, Anda bisa berhenti mengkhawatirkan
new
/delete
kinerja.sumber