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:
"seperti menggunakan variabel kondisi untuk memberi tahu utas agar bangun" Terdengar seperti pengaturan berdasarkan peristiwa / pengamat, bukan polling
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 mengingatkan PaintSystem
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 menelusuri PaintSystem'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:
when there's work to do:
for each thing:
apply a very specific and uniform operation to the thing
Sebagai lawan:
when one specific event happens:
do something with relevant thing
in relevant thing's event:
do some more things
in thing1's triggered by thing's event:
do some more things
in thing2's event triggerd by thing's event:
do some more things:
in thing3's event triggered by thing2's event:
do some more things
in thing4's event triggered by thing1's event:
cause a side effect which shouldn't be happening
in this order or from this thread.
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:
in thread dedicated to layout and painting:
when there's work to do:
for each widget that needs resizing/reposition:
resize/reposition thing to target size/position
mark appropriate grid cells as needing repainting
for each grid cell that needs repainting:
repaint cell
go back to sleep
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"