Pertanyaan Thread per koneksi vs Pola reaktor (dengan kolam thread)?


Saya ingin menulis permainan multiplayer sederhana sebagai bagian dari proyek pembelajaran C ++ saya.

Jadi saya pikir, karena saya melakukannya, saya ingin melakukannya tepat, dibandingkan dengan hanya menyelesaikannya.

Jika saya mengerti benar: Apache menggunakan arsitektur Thread-per-koneksi, sementara nginx menggunakan loop kejadian dan kemudian mendedikasikan seorang pekerja [x] untuk koneksi masuk. Saya kira nginx lebih bijaksana, karena mendukung tingkat konkurensi yang lebih tinggi. Kanan?

Saya juga menemukan ini analogi pintar, tapi saya tidak yakin apakah itu bisa diterapkan pada situasi saya. Analogi itu juga tampaknya sangat idealis. Saya jarang melihat komputer saya berjalan pada 100% CPU (bahkan dengan banyak Chrome tab terbuka, Photoshop dan apa yang tidak berjalan secara bersamaan)

Juga, saya telah menjumpai posting SO (entah bagaimana menghilang dari sejarah saya) di mana seorang pengguna bertanya berapa banyak benang yang harus mereka gunakan, dan salah satu jawabannya adalah bahwa itu benar-benar dapat diterima untuk memiliki sekitar 700, bahkan hingga 10.000 utas. Pertanyaan ini terkait dengan JVM.

Jadi, mari kita memperkirakan basis pengguna fiktif sekitar 5.000 pengguna. Pendekatan mana yang seharusnya menjadi "yang paling bersamaan"?

  1. Pola reaktor menjalankan semuanya dalam satu utas.
  2. Pola reaktor dengan ulir-ulir (kira-kira, seberapa besar yang Anda sarankan seharusnya kolam benang?
  3. Membuat utas per sambungan dan kemudian menghancurkan utas yang diakhiri koneksi.

Saya akui opsi 2 terdengar seperti solusi terbaik bagi saya, tetapi saya sangat hijau dalam semua ini, jadi saya mungkin sedikit naif dan kehilangan beberapa cacat yang jelas. Juga, kedengarannya seperti itu bisa sangat sulit untuk diterapkan.

PS: Saya sedang mempertimbangkan untuk menggunakan POCO C ++ Perpustakaan. Menyarankan semua pustaka alternatif (seperti dorongan) baik-baik saja dengan saya. Namun, banyak yang mengatakan perpustakaan POCO sangat bersih dan mudah dimengerti. Jadi, saya lebih suka menggunakan yang itu, jadi saya bisa belajar tentang bagaimanas dari apa yang saya gunakan.


13
2018-01-14 11:56


asal


Jawaban:


Aplikasi Reaktif tentu skala lebih baik, ketika mereka ditulis dengan benar. Ini berarti

  • Jangan pernah memblokir thread reaktif:
    • Pemblokiran apa pun akan sangat menurunkan kinerja server Anda, Anda biasanya menggunakan sejumlah kecil benang reaktif, sehingga pemblokiran juga dapat dengan cepat menyebabkan deadlock.
    • Tidak ada mutex karena ini dapat memblokir, jadi tidak ada kondisi yang dapat dibagi bersama. Jika Anda memerlukan status berbagi, Anda harus membungkusnya dengan aktor atau yang serupa sehingga hanya satu utas yang memiliki akses ke negara bagian.
  • Semua pekerjaan di thread reaktif harus terikat cpu
    • Semua IO harus asynchronous atau dilakukan di kolam thread yang berbeda dan hasilnya dimasukkan kembali ke reaktor.
    • Ini berarti menggunakan futures atau callback untuk memproses balasan, gaya kode ini dapat dengan cepat menjadi tidak dapat dipahami jika Anda tidak terbiasa dan disiplin.
  • Semua pekerjaan dalam benang reaktif harus kecil
    • Untuk menjaga kesiapsiagaan server, semua tugas dalam reaktor harus kecil (dibatasi oleh waktu)
    • Pada mesin 8 inti, Anda tidak dapat membiarkan 8 tugas panjang tiba pada waktu yang sama karena tidak ada pekerjaan lain yang akan dimulai sampai selesai
    • Jika tugas bisa memakan waktu lama harus diputus (multitasking kooperatif)

Tugas dalam aplikasi reaktif dijadwalkan oleh aplikasi bukan sistem operasi, itulah sebabnya mereka bisa lebih cepat dan menggunakan lebih sedikit memori. Ketika Anda menulis aplikasi Reaktif, Anda mengatakan bahwa Anda tahu domain masalah dengan sangat baik sehingga Anda dapat mengatur dan menjadwalkan jenis pekerjaan ini lebih baik daripada sistem operasi dapat menjadwalkan utas melakukan pekerjaan yang sama dalam mode pemblokiran.

Saya penggemar besar arsitektur reaktif tetapi mereka datang dengan biaya. Saya tidak yakin saya akan menulis aplikasi c ++ pertama saya sebagai reaktif, saya biasanya mencoba untuk belajar satu hal pada satu waktu.

Jika Anda memutuskan untuk menggunakan arsitektur reaktif, gunakan kerangka kerja yang baik yang akan membantu Anda merancang dan menyusun kode Anda atau Anda akan berakhir dengan spaghetti. Hal yang harus dicari adalah:

  • Apa unit kerja itu?
  • Seberapa mudah menambahkan pekerjaan baru? dapatkah itu hanya datang dari peristiwa eksternal (misalnya permintaan jaringan)
  • Seberapa mudahnya memecah kerja menjadi bagian yang lebih kecil?
  • Seberapa mudahnya memproses hasil kerja ini?
  • Seberapa mudahnya memindahkan kode pemblokiran ke kumpulan utas lainnya dan masih memproses hasilnya?

Saya tidak dapat merekomendasikan perpustakaan C ++ untuk ini, sekarang saya melakukan pengembangan server saya di Scala dan Akka yang menyediakan semua ini dengan perpustakaan masa depan composable yang sangat baik untuk menjaga kode tetap bersih.

Best of luck belajar C ++ dan yang pernah Anda pilih.


11
2017-07-12 13:31



Opsi 2 paling efisien akan menempati perangkat keras Anda. Ini artikel klasik, berumur sepuluh tahun tapi masih bagus.

http://www.kegel.com/c10k.html

Kombinasi perpustakaan terbaik hari ini untuk menyusun aplikasi dengan konkurensi dan menunggu asynchronous adalah Boost Thread plus Boost ASIO. Anda juga bisa mencoba C ++ 11 std thread perpustakaan, dan std mutex (tetapi Meningkatkan ASIO lebih baik daripada mutexes dalam banyak kasus, hanya selalu callback ke thread yang sama dan Anda tidak perlu kawasan yang dilindungi). Menjauh dari std future, karena rusak:

http://bartoszmilewski.com/2009/03/03/broken-promises-c0x-futures/

Jumlah optimal untaian dalam rangkaian ulir adalah satu utas per inti CPU. 8 core -> 8 utas. Plus mungkin beberapa tambahan, jika Anda berpikir mungkin thread threadpool Anda mungkin memanggil operasi pemblokiran kadang-kadang.


7
2018-01-14 12:29



FWIW, Poco mendukung opsi 2 (ParallelReactor) sejak versi 1.5.1


2
2018-02-04 05:09



Saya pikir opsi 2 adalah yang terbaik. Untuk tuning ukuran kolam renang, saya pikir kolam renang harus adaptif. Itu harus dapat menelurkan lebih banyak benang (dengan beberapa batas keras tinggi) dan menghapus benang yang berlebihan di saat aktivitas rendah.


1
2018-01-14 11:59



sebagai analogi yang Anda kaitkan dengan (dan komentarnya) sarankan. ini tergantung pada aplikasi. sekarang apa yang Anda bangun di sini adalah server game. mari kita analisa itu.

server game (umumnya) melakukan banyak perhitungan I / O dan relatif sedikit, sehingga mereka jauh dari 100% aplikasi CPU. di sisi lain mereka juga biasanya mengubah nilai dalam beberapa basis data (model "dunia game"). semua pemain membuat membaca dan menulis ke database ini. yang merupakan masalah persimpangan dalam analogi.

jadi sementara Anda dapat memperoleh beberapa dari menangani I / O di thread terpisah, Anda juga akan kehilangan dari memiliki thread terpisah mengakses database yang sama dan menunggu gemboknya.

jadi pilihan 1 atau 2 dapat diterima dalam situasi Anda. untuk alasan skalabilitas saya tidak akan merekomendasikan opsi 3.


1
2018-01-14 12:26