Apakah ada skenario di mana pemungutan suara untuk acara akan lebih baik daripada menggunakan pola pengamat ? Saya takut menggunakan polling dan hanya akan mulai menggunakannya jika seseorang memberi saya skenario yang bagus. Yang bisa saya pikirkan adalah bagaimana pola pengamat lebih baik daripada polling. Pertimbangkan skenario ini:
Anda sedang memprogram simulator mobil. Mobil adalah sebuah benda. Begitu mobil menyala, Anda ingin memutar klip suara "vroom vroom".
Anda dapat memodelkan ini dalam dua cara:
Polling : Polling objek mobil setiap detik untuk melihat apakah itu menyala. Saat aktif, putar klip suara.
Pola pengamat : Jadikan mobil sebagai Subjek dari pola pengamat. Mintalah ia mempublikasikan acara "aktif" kepada semua pengamat saat itu sendiri menyala. Buat objek suara baru yang mendengarkan mobil. Apakah itu menerapkan panggilan balik "on", yang memutar klip suara.
Dalam hal ini, saya pikir pola pengamat menang. Pertama, pemungutan suara lebih intensif prosesor. Kedua, klip suara tidak langsung menyala ketika mobil menyala. Mungkin ada kesenjangan 1 detik karena periode pemungutan suara.
sumber
Jawaban:
Bayangkan Anda ingin diberitahu tentang setiap siklus mesin, mis. Untuk menampilkan pengukuran RPM kepada pengemudi.
Pola pengamat: Mesin menerbitkan acara "putaran mesin" kepada semua pengamat untuk setiap siklus. Buat pendengar yang menghitung acara dan memperbarui tampilan RPM.
Polling: Tampilan RPM meminta engine secara berkala untuk penghitung siklus engine, dan memperbarui tampilan RPM.
Dalam hal ini, pola pengamat mungkin akan hilang: siklus mesin adalah frekuensi tinggi, proses prioritas tinggi, Anda tidak ingin menunda atau menghentikan proses itu hanya untuk memperbarui tampilan. Anda juga tidak ingin meremukkan kumpulan utas dengan acara siklus mesin.
PS: Saya juga sering menggunakan pola polling dalam pemrograman terdistribusi:
Pola pengamat: Proses A mengirim pesan ke proses B yang mengatakan "setiap kali peristiwa E terjadi, kirim pesan ke Proses A".
Pola polling: Proses A secara teratur mengirim pesan ke proses B yang mengatakan "jika Anda mengalami E sejak terakhir kali saya melakukan polling, kirimkan saya pesan sekarang".
Pola polling menghasilkan sedikit lebih banyak beban jaringan. Tetapi pola pengamat juga memiliki kelemahan:
sumber
Pemungutan suara lebih baik jika proses pemungutan suara berjalan jauh lebih lambat daripada yang dipungutnya. Jika Anda menulis acara ke basis data, sering kali lebih baik menyurvei semua produser acara Anda, mengumpulkan semua peristiwa yang telah terjadi sejak jajak pendapat terakhir, lalu menuliskannya dalam satu transaksi. Jika Anda mencoba menulis setiap peristiwa saat itu terjadi, Anda mungkin tidak dapat mengikuti dan akhirnya akan mengalami masalah ketika antrian masukan Anda terisi. Ini juga lebih masuk akal dalam sistem terdistribusi longgar, di mana latensi tinggi atau pengaturan koneksi dan penghancuran mahal. Saya menemukan sistem pemungutan suara lebih mudah untuk ditulis dan dipahami, tetapi dalam kebanyakan situasi, pengamat atau konsumen yang didorong oleh peristiwa tampaknya menawarkan kinerja yang lebih baik (dalam pengalaman saya).
sumber
Polling jauh lebih mudah untuk bekerja melalui jaringan ketika koneksi mungkin gagal, server bisa selesai dll. Ingat pada akhir hari soket TCP membutuhkan "polling" menyimpan pesan live-live jika tidak, server akan menganggap klien telah pergi.
Polling juga bagus ketika Anda ingin menjaga UI diperbarui, tetapi objek yang mendasarinya berubah sangat cepat , tidak ada gunanya memperbarui UI lebih dari beberapa kali per detik di sebagian besar aplikasi.
Asalkan server dapat merespons "tidak ada perubahan" dengan biaya yang sangat rendah dan Anda tidak terlalu sering melakukan polling dan Anda tidak memiliki 1000-an klien polling, kemudian polling berfungsi dengan sangat baik dalam kehidupan nyata.
Namun untuk kasus " dalam memori ", saya menggunakan pola pengamat karena biasanya paling tidak berfungsi.
sumber
Polling memiliki beberapa kelemahan, pada dasarnya Anda sudah menyatakannya dalam pertanyaan Anda.
Namun, ini bisa menjadi solusi yang lebih baik, ketika Anda ingin benar-benar memisahkan yang dapat diamati dari pengamat mana pun. Tetapi kadang-kadang mungkin lebih baik menggunakan pembungkus yang dapat diamati untuk objek yang akan diamati dalam kasus seperti itu.
Saya hanya akan menggunakan polling ketika diamati tidak dapat diamati dengan interaksi objek, yang sering terjadi ketika query database misalnya, di mana Anda tidak dapat memiliki panggilan balik. Masalah lain mungkin multithreading, di mana sering kali lebih aman untuk memilih dan memproses pesan daripada memanggil objek secara langsung, untuk menghindari masalah konkurensi.
sumber
Untuk contoh yang baik tentang kapan polling mengambil alih dari notifikasi, lihat tumpukan jaringan sistem operasi.
Itu adalah masalah besar bagi Linux ketika tumpukan jaringan mengaktifkan NAPI, API jaringan yang memungkinkan driver untuk beralih dari mode interupsi (notifikasi) ke mode polling.
Dengan beberapa antarmuka Ethernet gigabit, interupsi akan sering membebani CPU, menyebabkan sistem berjalan lebih lambat dari yang seharusnya. Dengan polling, kartu jaringan mengumpulkan paket dalam buffer sampai polling atau kartu bahkan menulis paket ke dalam memori melalui DMA. Kemudian ketika sistem operasi siap itu polling kartu untuk semua data dan melakukan pemrosesan TCP / IP standar.
Mode polling memungkinkan CPU untuk mengumpulkan data Ethernet pada kecepatan pemrosesan maksimum tanpa beban interupsi yang tidak berguna. Mode interupsi memungkinkan CPU untuk menganggur di antara paket ketika pekerjaan tidak begitu sibuk.
Rahasianya adalah kapan harus beralih dari satu mode ke mode lainnya. Setiap mode memiliki kelebihan dan harus digunakan di tempat yang tepat.
sumber
Saya suka polling! Apakah saya? Iya nih! Apakah saya? Iya nih! Apakah saya? Iya nih! Apakah saya masih? Iya nih! Bagaimana dengan sekarang? Iya nih!
Seperti yang disebutkan orang lain, ini bisa sangat tidak efisien jika Anda polling hanya untuk mendapatkan kembali kondisi yang sama tidak berubah berulang kali. Itulah resep untuk membakar siklus CPU dan secara signifikan mempersingkat masa pakai baterai pada perangkat seluler. Tentu saja itu tidak sia-sia jika Anda kembali ke keadaan baru dan bermakna setiap saat dengan kecepatan yang tidak lebih cepat dari yang diinginkan.
Tapi alasan utama saya suka polling adalah karena kesederhanaan dan sifatnya yang dapat diprediksi. Anda dapat menelusuri kode dan dengan mudah melihat kapan dan di mana hal-hal akan terjadi, dan di utas apa. Jika, secara teoritis, kami hidup di dunia di mana pemungutan suara adalah limbah yang dapat diabaikan (meskipun kenyataannya jauh dari itu), maka saya percaya itu akan menyederhanakan pemeliharaan kode kesepakatan yang luar biasa. Dan itulah manfaat dari pemungutan suara dan penarikan seperti yang saya lihat jika kita dapat mengabaikan kinerja, meskipun kita tidak seharusnya dalam hal ini.
Ketika saya mulai pemrograman di era DOS, permainan kecil saya berputar di sekitar polling. Saya menyalin beberapa kode rakitan dari sebuah buku yang saya hampir tidak mengerti terkait dengan gangguan keyboard dan membuatnya menyimpan buffer status keyboard, di mana titik loop utama saya selalu polling. Apakah kunci naik turun? Nggak. Apakah kunci naik turun? Nggak. Bagaimana kalau sekarang? Nggak. Sekarang? Iya nih. Oke, pindahkan pemain.
Dan sementara sangat boros, saya menemukan bahwa jauh lebih mudah untuk dipikirkan dibandingkan dengan hari-hari ini multi-tasking dan event-driven programming. Saya tahu persis kapan dan di mana hal-hal akan terjadi setiap saat dan lebih mudah untuk menjaga frame rate stabil dan dapat diprediksi tanpa cegukan.
Jadi sejak itu saya selalu berusaha menemukan cara untuk mendapatkan beberapa manfaat dan prediktabilitas dari hal itu tanpa benar-benar membakar siklus CPU, seperti menggunakan variabel kondisi untuk memberi tahu thread agar bangun pada titik mana mereka dapat menarik status baru, lakukan hal mereka, dan kembali tidur menunggu untuk diberitahu lagi.
Dan entah bagaimana saya menemukan antrian acara jauh lebih mudah untuk dikerjakan dengan setidaknya dari pola pengamat, meskipun mereka masih tidak membuatnya begitu mudah untuk memprediksi di mana Anda akan berakhir atau apa yang akhirnya terjadi. Mereka setidaknya memusatkan aliran kontrol penanganan peristiwa ke beberapa area utama dalam sistem dan selalu menangani peristiwa tersebut di utas yang sama alih-alih memantul dari satu fungsi ke suatu tempat yang sepenuhnya terpencil dan tidak terduga, tiba-tiba di luar luar dari pusat kejadian yang menangani utas. Jadi dikotomi tidak selalu harus antara pengamat dan pemungutan suara. Antrian acara adalah semacam jalan tengah di sana.
Tapi ya, entah bagaimana saya merasa jauh lebih mudah untuk beralasan tentang sistem yang melakukan hal-hal yang secara analog lebih dekat dengan jenis aliran kontrol yang dapat diprediksi yang saya miliki ketika saya polling berabad-abad yang lalu, sementara hanya menangkal kecenderungan pekerjaan yang terjadi di saat tidak ada perubahan status yang terjadi. Jadi ada manfaatnya jika Anda bisa melakukannya dengan cara yang tidak membakar siklus CPU seperti dengan variabel kondisi.
Loop Homogen
Baiklah, saya mendapat komentar yang bagus dari
Josh Caswell
yang menunjukkan beberapa kesalahan dalam jawaban saya:Secara teknis variabel kondisi itu sendiri menerapkan pola pengamat untuk membangunkan / memberi tahu utas, sehingga menyebut "jajak pendapat" mungkin akan sangat menyesatkan. Tapi saya menemukan itu memberikan manfaat serupa yang saya temukan sebagai polling dari hari-hari DOS (hanya dalam hal aliran kontrol dan prediktabilitas). Saya akan mencoba menjelaskannya dengan lebih baik.
Apa yang saya temukan menarik pada masa itu adalah bahwa Anda dapat melihat bagian kode atau menelusuri melalui itu dan berkata, "Oke, seluruh bagian ini didedikasikan untuk menangani acara keyboard. Tidak ada hal lain yang akan terjadi di bagian kode ini Dan saya tahu persis apa yang akan terjadi sebelumnya, dan saya tahu persis apa yang akan terjadi setelahnya (fisika dan rendering, misalnya). " Polling dari status keyboard memberi Anda semacam sentralisasi aliran kontrol sejauh menangani apa yang harus terjadi dalam menanggapi peristiwa eksternal ini. Kami tidak segera merespons acara eksternal ini. Kami menanggapinya dengan nyaman.
Ketika kami menggunakan sistem berbasis-push berdasarkan pola Observer, kami sering kehilangan manfaat itu. Kontrol mungkin diubah ukurannya yang memicu peristiwa perubahan ukuran. Ketika kami menelusuri, kami menemukan kami berada di dalam kontrol eksotis yang melakukan banyak hal kebiasaan dalam mengubah ukurannya yang memicu lebih banyak peristiwa. Kami akhirnya benar-benar terkejut melacak semua peristiwa yang mengalir ke mana kita berakhir dalam sistem. Selain itu, kami mungkin menemukan bahwa semua ini bahkan tidak terjadi secara konsisten di utas yang diberikan karena utas A mungkin mengubah ukuran kontrol di sini sementara utas B juga mengubah ukuran kontrol di kemudian hari. Jadi saya selalu menemukan ini sangat sulit untuk dipikirkan tentang betapa sulitnya untuk memprediksi di mana semuanya terjadi serta apa yang akan terjadi.
Antrian acara sedikit lebih mudah bagi saya untuk dipikirkan karena menyederhanakan di mana semua hal ini terjadi setidaknya pada tingkat utas. Namun, banyak hal yang berbeda dapat terjadi. Sebuah antrian acara dapat berisi campuran eklektik peristiwa untuk diproses, dan masing-masing peristiwa masih dapat mengejutkan kita seperti kaskade peristiwa yang terjadi, urutan prosesnya, dan bagaimana kita akhirnya memantul di seluruh tempat dalam basis kode. .
Apa yang saya anggap "paling dekat" dengan polling tidak akan menggunakan antrian acara tetapi akan menunda jenis pemrosesan yang sangat homogen. A
PaintSystem
mungkin diperingatkan melalui variabel kondisi bahwa ada pekerjaan pengecatan yang harus dilakukan untuk mengecat ulang sel-sel grid tertentu dari sebuah jendela, di mana titik itu melakukan loop berurutan sederhana melalui sel-sel dan mengecat ulang semua yang ada di dalamnya dalam z-order yang tepat. Mungkin ada satu tingkat panggilan tipuan / pengiriman dinamis di sini untuk memicu acara cat di setiap widget yang berada di sel yang perlu dicat ulang, tapi hanya itu - hanya satu lapisan panggilan tidak langsung. Variabel kondisi menggunakan pola pengamat untuk mengingatkanPaintSystem
bahwa ia memiliki pekerjaan yang harus dilakukan, tetapi tidak menentukan lebih dari itu, danPaintSystem
dikhususkan untuk satu seragam, tugas yang sangat homogen pada saat itu. Ketika kita men-debug dan menelusuriPaintSystem's
kode, kita tahu bahwa tidak ada hal lain yang akan terjadi kecuali melukis.Jadi itu sebagian besar tentang mendapatkan sistem ke mana Anda memiliki hal-hal ini melakukan loop homogen atas data menerapkan tanggung jawab yang sangat tunggal, bukan loop non-homogen atas jenis data yang berbeda melakukan berbagai tanggung jawab seperti yang mungkin kita dapatkan dengan proses antrian acara.
Kami bertujuan untuk hal semacam ini:
Sebagai lawan:
Dan seterusnya. Dan itu tidak harus menjadi satu utas per tugas. Satu utas mungkin menerapkan logika tata letak (pengubahan ukuran / reposisi) untuk kontrol GUI dan mengecatnya, tetapi mungkin tidak menangani klik keyboard atau mouse. Jadi Anda bisa melihat ini sebagai hanya meningkatkan homogenitas antrian acara. Tetapi kita tidak harus menggunakan antrian acara dan juga fungsi pengubahan ukuran dan pengecatan interleave. Kita bisa melakukan seperti:
Jadi pendekatan di atas hanya menggunakan variabel kondisi untuk memberi tahu thread ketika ada pekerjaan yang harus dilakukan, tetapi itu tidak interleave berbagai jenis peristiwa (mengubah ukuran dalam satu loop, melukis di loop lain, bukan campuran keduanya) dan tidak Jangan repot-repot untuk mengomunikasikan apa pekerjaan itu sebenarnya yang perlu dilakukan (utas "menemukan" bahwa setelah bangun tidur dengan melihat keadaan ECS di seluruh sistem). Setiap loop yang dilakukannya kemudian sangat homogen, membuatnya mudah untuk berpikir tentang urutan di mana segala sesuatu terjadi.
Saya tidak yakin apa yang harus disebut jenis pendekatan ini. Saya belum pernah melihat mesin GUI lain melakukan ini dan itu semacam pendekatan eksotis saya sendiri. Tetapi sebelumnya ketika saya mencoba untuk mengimplementasikan kerangka kerja GUI multithreaded menggunakan pengamat atau antrian acara, saya mengalami kesulitan luar biasa men-debug itu dan juga mengalami beberapa kondisi lomba yang tidak jelas dan kebuntuan yang tidak cukup pintar untuk saya perbaiki dengan cara yang membuat saya merasa percaya diri tentang solusinya (beberapa orang mungkin dapat melakukan ini, tetapi saya tidak cukup pintar). Desain iterasi pertama saya hanya memanggil slot langsung melalui sinyal dan beberapa slot kemudian akan menelurkan thread lain untuk melakukan pekerjaan async, dan itu yang paling sulit untuk dipikirkan dan saya tersandung kondisi balapan dan deadlock. Iterasi kedua menggunakan antrian acara dan itu sedikit lebih mudah untuk dipikirkan, tetapi tidak cukup mudah bagi otak saya untuk melakukannya tanpa masih mengalami kebuntuan yang tidak jelas dan kondisi ras. Iterasi ketiga dan terakhir menggunakan pendekatan yang dijelaskan di atas, dan akhirnya memungkinkan saya untuk membuat kerangka GUI multithreaded yang bahkan orang bodoh bodoh seperti saya dapat menerapkan dengan benar.
Kemudian jenis desain GUI multithreaded final ini memungkinkan saya untuk menemukan sesuatu yang lain yang jauh lebih mudah untuk dipikirkan dan dihindari jenis kesalahan yang cenderung saya buat, dan salah satu alasan saya merasa jauh lebih mudah untuk dipikirkan pada paling tidak karena loop yang homogen ini dan bagaimana mereka agak menyerupai aliran kontrol yang mirip dengan ketika saya melakukan polling pada hari-hari DOS (walaupun itu tidak benar-benar polling dan hanya melakukan pekerjaan ketika ada pekerjaan yang harus dilakukan). Idenya adalah untuk bergerak sejauh mungkin dari model penanganan peristiwa yang mungkin yang menyiratkan loop non-homogen, efek samping non-homogen, aliran kontrol non-homogen, dan untuk bekerja lebih dan lebih ke arah loop homogen yang beroperasi secara seragam pada data homogen dan mengisolasi dan menyatukan efek samping dengan cara yang membuatnya lebih mudah untuk hanya fokus pada "apa"
sumber
LayoutSystem
yang biasanya tidur, tetapi ketika pengguna mengubah ukuran kontrol, itu akan menggunakan variabel kondisi untuk membangunkanLayoutSystem
. KemudianLayoutSystem
mengubah ukuran semua kontrol yang diperlukan dan kembali tidur. Dalam prosesnya, daerah persegi panjang widget berada ditandai sebagai membutuhkan pembaruan, di mana titik aPaintSystem
bangun dan melewati daerah persegi panjang, mengecat ulang yang perlu digambar ulang dalam loop berurutan datar.Saya memberi Anda gambaran lebih lanjut tentang cara berpikir konseptual tentang derai pengamat. Pikirkan skenario seperti berlangganan saluran youtube. Ada sejumlah pengguna yang berlangganan saluran dan begitu ada pembaruan di saluran yang terdiri dari banyak video, pelanggan akan diberi tahu bahwa ada perubahan pada saluran tertentu ini. Jadi kami menyimpulkan bahwa jika saluran SUBJECT yang memiliki kemampuan untuk berlangganan, berhenti berlangganan dan beri tahu semua OBSERVER yang terdaftar di saluran.
sumber