ฉันรักการเลือกตั้ง! ฉัน ใช่ ฉัน ใช่ ฉัน ใช่ ฉันยัง ใช่ แล้วตอนนี้ล่ะ? ใช่
ดังที่คนอื่น ๆ พูดถึงมันอาจจะไร้ประสิทธิภาพอย่างไม่น่าเชื่อถ้าคุณโพลเท่านั้นที่จะได้รับสถานะที่ไม่เปลี่ยนแปลงเหมือนเดิมซ้ำไปซ้ำมา นี่เป็นสูตรสำหรับเบิร์นซีพียูและทำให้อายุการใช้งานแบตเตอรี่สั้นลงอย่างเห็นได้ชัดบนอุปกรณ์พกพา แน่นอนว่ามันไม่สิ้นเปลืองหากคุณได้รับสถานะใหม่และมีความหมายทุกครั้งในอัตราที่ไม่เร็วกว่าที่ต้องการ
แต่เหตุผลหลักที่ฉันรักการลงคะแนนเลือกตั้งเป็นเพราะความเรียบง่ายและธรรมชาติที่คาดเดาได้ คุณสามารถติดตามรหัสและดูได้ง่ายว่าจะเกิดอะไรขึ้นเมื่อไรและที่ไหนและในหัวข้อใด ถ้าในทางทฤษฎีเราอาศัยอยู่ในโลกที่การเลือกตั้งเป็นของเสียเพียงเล็กน้อย (แม้ว่าความเป็นจริงจะอยู่ไกลจากมัน) จากนั้นฉันเชื่อว่ามันจะทำให้การจัดการรหัสง่ายขึ้นมาก และนั่นคือประโยชน์ของการสำรวจและการดึงตามที่ฉันเห็นถ้าเราสามารถเพิกเฉยต่อประสิทธิภาพแม้ว่าเราจะไม่ควรในกรณีนี้
เมื่อฉันเริ่มเขียนโปรแกรมในยุค DOS เกมเล็ก ๆ ของฉันหมุนไปรอบ ๆ หน่วยเลือกตั้ง ฉันคัดลอกรหัสแอสเซมบลีบางส่วนจากหนังสือที่ฉันแทบจะไม่เข้าใจเกี่ยวกับการขัดจังหวะของแป้นพิมพ์และทำให้มันเก็บบัฟเฟอร์สถานะแป้นพิมพ์ ณ จุดนี้ห่วงหลักของฉันมักจะทำการสำรวจเสมอ คีย์ขึ้นลงหรือไม่ Nope คีย์ขึ้นลงหรือไม่ Nope แล้วตอนนี้ล่ะ? Nope ตอนนี้? ใช่. โอเคย้ายเครื่องเล่น
และในขณะที่สิ้นเปลืองอย่างไม่น่าเชื่อฉันพบว่าเหตุผลง่ายกว่าเมื่อเปรียบเทียบกับการเขียนโปรแกรมแบบมัลติทาสกิ้งและการขับเคลื่อนเหตุการณ์ ฉันรู้ว่าเมื่อไหร่และที่ไหนสิ่งที่จะเกิดขึ้นตลอดเวลาและมันง่ายกว่าที่จะรักษาอัตราเฟรมให้คงที่และคาดการณ์ได้โดยไม่ต้องสะดุด
ดังนั้นตั้งแต่นั้นมาฉันพยายามหาวิธีที่จะได้รับประโยชน์และการคาดการณ์บางอย่างโดยไม่ต้องเผาวงจรซีพียูเช่นการใช้ตัวแปรเงื่อนไขเพื่อแจ้งเธรดให้ตื่นขึ้นมาถึงจุดที่พวกเขาสามารถดึงสถานะใหม่ ทำสิ่งที่พวกเขาและกลับไปนอนเพื่อรอรับการแจ้งเตือนอีกครั้ง
และบางครั้งฉันก็พบว่าคิวเหตุการณ์นั้นง่ายกว่ามากที่จะทำงานกับรูปแบบการสังเกตการณ์แม้ว่าพวกเขาจะยังไม่ทำให้คาดเดาได้ง่ายว่าคุณจะไปที่ไหนหรือเกิดอะไรขึ้น อย่างน้อยพวกเขาก็รวมศูนย์ควบคุมการจัดการเหตุการณ์ไปยังพื้นที่สำคัญสองสามแห่งในระบบและจัดการกับเหตุการณ์เหล่านั้นในเธรดเดียวกันเสมอแทนที่จะเด้งจากฟังก์ชั่นหนึ่งไปยังที่อื่นที่ห่างไกลอย่างสมบูรณ์และไม่คาดคิดทั้งหมด ดังนั้นการแบ่งแยกขั้วจึงไม่จำเป็นต้องอยู่ระหว่างผู้สังเกตการณ์กับการเลือกตั้งเสมอไป คิวของเหตุการณ์นั้นเป็นพื้นกลางตรงนั้น
แต่ใช่ฉันก็พบว่ามันง่ายกว่ามากที่จะให้เหตุผลเกี่ยวกับระบบที่ทำสิ่งต่าง ๆ ที่ใกล้เคียงกับกระแสการควบคุมแบบคาดเดาได้ที่ฉันเคยมีเมื่อตอนที่ฉันสำรวจความคิดเห็นเมื่อหลายปีก่อนในขณะที่เพียงต่อต้านแนวโน้ม ครั้งเมื่อไม่มีการเปลี่ยนแปลงสถานะ ดังนั้นมันจึงมีประโยชน์ถ้าคุณสามารถทำมันในแบบที่ไม่ทำให้รอบการทำงานของ CPU ไม่จำเป็นต้องเหมือนกับตัวแปรเงื่อนไข
ลูปที่เป็นเนื้อเดียวกัน
เอาล่ะฉันได้รับความคิดเห็นที่ดีจากJosh Caswell
สิ่งที่ชี้ให้เห็นความโง่ในคำตอบของฉัน:
"ชอบใช้ตัวแปรเงื่อนไขเพื่อแจ้งให้เธรดตื่น" เสียงเหมือนการจัดเรียงตามผู้สังเกตการณ์ไม่ใช่การสำรวจ
ในทางเทคนิคแล้วตัวแปรเงื่อนไขกำลังใช้รูปแบบผู้สังเกตการณ์เพื่อปลุก / แจ้งเตือนเธรดดังนั้นการเรียกว่า "การสำรวจ" อาจจะทำให้เข้าใจผิดอย่างไม่น่าเชื่อ แต่ฉันพบว่ามันให้ประโยชน์คล้าย ๆ กันกับที่ฉันค้นพบจากการสำรวจจาก DOS วัน (ในแง่ของการควบคุมการไหลและการคาดการณ์) ฉันจะพยายามอธิบายให้ดีขึ้น
สิ่งที่ฉันพบว่าน่าสนใจในสมัยนั้นคือคุณสามารถดูส่วนของรหัสหรือติดตามมันและพูดว่า"โอเคทุกส่วนนี้มีไว้สำหรับจัดการกับเหตุการณ์แป้นพิมพ์ไม่มีอะไรเกิดขึ้นในส่วนของรหัสนี้ และฉันรู้ว่าสิ่งที่จะเกิดขึ้นมาก่อนและฉันรู้ว่าสิ่งที่จะเกิดขึ้นหลังจาก (ฟิสิกส์และการแสดงผลเช่น) การสำรวจสถานะของแป้นพิมพ์ทำให้คุณมีการรวมศูนย์การไหลของการควบคุมเท่าที่การจัดการสิ่งที่ควรดำเนินการเพื่อตอบสนองต่อเหตุการณ์ภายนอกนี้ เราไม่ตอบสนองต่อกิจกรรมภายนอกนี้ทันที เราตอบกลับตามความสะดวกของเรา
เมื่อเราใช้ระบบฐานแบบอิงจากรูปแบบการสังเกตการณ์เรามักสูญเสียผลประโยชน์เหล่านั้น การควบคุมอาจได้รับการปรับขนาดซึ่งก่อให้เกิดเหตุการณ์การปรับขนาด เมื่อเราติดตามมันเราพบว่าเราอยู่ในการควบคุมที่แปลกใหม่ซึ่งทำสิ่งที่กำหนดเองจำนวนมากในการปรับขนาดซึ่งทำให้เกิดเหตุการณ์มากขึ้น เราจบลงด้วยการประหลาดใจอย่างสมบูรณ์ในการติดตามเหตุการณ์ที่เกิดขึ้นทั้งหมดเหล่านี้ว่าเราอยู่ที่ไหนในระบบ นอกจากนี้เราอาจพบว่าทั้งหมดนี้ไม่ได้เกิดขึ้นอย่างสม่ำเสมอในเธรดใด ๆ เนื่องจากเธรด A อาจปรับขนาดตัวควบคุมที่นี่ในขณะที่เธรด B ยังปรับขนาดการควบคุมในภายหลัง ดังนั้นฉันมักจะพบว่ามันยากมากที่จะให้เหตุผลว่ามันยากแค่ไหนที่จะทำนายว่าทุกสิ่งเกิดขึ้นรวมถึงสิ่งที่จะเกิดขึ้น
คิวเหตุการณ์นั้นง่ายกว่าสำหรับฉันเล็กน้อยเพราะมันทำให้สิ่งเหล่านี้เกิดขึ้นอย่างน้อยที่สุดในระดับเธรด อย่างไรก็ตามสิ่งที่แตกต่างกันอาจเกิดขึ้น คิวเหตุการณ์อาจมีการผสมผสานของเหตุการณ์ที่ต้องดำเนินการและแต่ละเหตุการณ์ยังคงทำให้เราประหลาดใจกับเหตุการณ์ที่เกิดขึ้นลำดับการประมวลผลและวิธีการที่เราตีกลับทั่วสถานที่ในรหัสฐาน .
สิ่งที่ฉันพิจารณาว่า "ใกล้เคียงที่สุด" กับการสำรวจความคิดเห็นจะไม่ใช้คิวเหตุการณ์ แต่จะเลื่อนการประมวลผลที่เป็นเนื้อเดียวกันออกไป A PaintSystem
อาจได้รับการแจ้งเตือนผ่านตัวแปรเงื่อนไขที่มีงานวาดภาพที่ต้องทำเพื่อทาสีเซลล์กริดบางอันของหน้าต่าง ณ จุดนั้นมันจะวนลูปเรียงลำดับอย่างง่ายผ่านเซลล์และ repaints ทุกอย่างที่อยู่ในลำดับ z อาจมีระดับหนึ่งของการเรียกทางอ้อม / การจัดส่งแบบไดนามิกที่นี่เพื่อทริกเกอร์เหตุการณ์การทาสีในแต่ละวิดเจ็ตที่อยู่ในเซลล์ที่จำเป็นต้องทาสีใหม่ แต่นั่นเป็นเพียงการโทรทางอ้อมเพียงชั้นเดียว ตัวแปรเงื่อนไขใช้รูปแบบของผู้สังเกตการณ์เพื่อเตือนPaintSystem
ว่ามันมีงานต้องทำ แต่ไม่ได้ระบุอะไรมากกว่านั้นและPaintSystem
อุทิศให้กับงานที่เป็นหนึ่งเดียวซึ่งเป็นเนื้อเดียวกันมาก ณ จุดนั้น เมื่อเราทำการดีบั๊กและติดตามPaintSystem's
รหัสเรารู้ว่าจะไม่มีอะไรเกิดขึ้นนอกจากการวาดภาพ
ดังนั้นส่วนใหญ่เกี่ยวกับการทำให้ระบบลงไปถึงจุดที่คุณมีสิ่งเหล่านี้ที่มีลูปเป็นเนื้อเดียวกันกับข้อมูลโดยใช้ความรับผิดชอบเอกเทศมากกว่าแทนที่จะเป็นลูปที่ไม่เป็นเนื้อเดียวกันกับข้อมูลประเภทที่แตกต่างกัน
เรามุ่งที่จะทำสิ่งนี้:
when there's work to do:
for each thing:
apply a very specific and uniform operation to the thing
ตรงข้ามกับ:
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.
และอื่น ๆ และไม่จำเป็นต้องเป็นหนึ่งเธรดต่องาน เธรดหนึ่งอาจใช้ตรรกะเค้าโครง (ปรับขนาด / เปลี่ยนตำแหน่ง) สำหรับการควบคุม GUI และวาดใหม่ แต่อาจไม่รองรับการคลิกแป้นพิมพ์หรือเมาส์ ดังนั้นคุณสามารถดูที่นี่เป็นเพียงการปรับปรุงความสม่ำเสมอของคิวเหตุการณ์ แต่เราไม่จำเป็นต้องใช้คิวเหตุการณ์และการปรับขนาดและแทรกสอดระหว่างฟังก์ชัน เราสามารถทำเช่น:
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
ดังนั้นวิธีการข้างต้นใช้ตัวแปรเงื่อนไขเพื่อแจ้งเธรดเมื่อมีงานต้องทำ แต่มันไม่ได้สอดแทรกเหตุการณ์ประเภทต่าง ๆ (ปรับขนาดในวงวนหนึ่ง, ทาสีในวงอื่น, ไม่ใช่วงดนตรีผสมกันทั้งคู่) และมันไม่ได้ ' ไม่ต้องการสื่อสารสิ่งที่งานนั้นเป็นสิ่งที่จำเป็นต้องทำ (เธรด "ค้นพบ" ซึ่งเมื่อตื่นขึ้นมาโดยดูที่สถานะของทั้งระบบของ ECS) แต่ละวงที่มันทำนั้นมีลักษณะเหมือนกันมากในธรรมชาติทำให้ง่ายต่อการให้เหตุผลเกี่ยวกับลำดับที่ทุกอย่างเกิดขึ้น
ฉันไม่แน่ใจว่าจะเรียกวิธีนี้ได้อย่างไร ฉันไม่เห็นเอ็นจิน GUI อื่นทำเช่นนี้และมันเป็นวิธีการแปลกใหม่ของฉันเอง แต่ก่อนที่เมื่อฉันพยายามใช้กรอบ GUI แบบมัลติเธรดโดยใช้ผู้สังเกตการณ์หรือคิวเหตุการณ์ฉันมีความยากลำบากอย่างมากในการแก้ไขข้อบกพร่องและยังวิ่งไปสู่สภาพการแข่งขันที่คลุมเครือและการหยุดชะงักที่ฉันไม่ฉลาดพอที่จะแก้ไขได้อย่างมั่นใจ เกี่ยวกับการแก้ปัญหา (บางคนอาจจะสามารถทำสิ่งนี้ แต่ฉันไม่ฉลาดพอ) การออกแบบการวนซ้ำครั้งแรกของฉันเรียกว่าสล็อตโดยตรงผ่านสัญญาณและบางสล็อตก็จะวางไข่เธรดอื่น ๆ เพื่อทำงาน async และนั่นเป็นเหตุผลที่ยากที่สุดในการทำเช่นนั้นและฉันก็สะดุดสภาพการแข่งขันและการหยุดชะงัก การวนซ้ำครั้งที่สองใช้คิวเหตุการณ์และนั่นง่ายกว่าที่จะให้เหตุผล แต่มันก็ไม่ง่ายพอที่สมองของฉันจะทำได้โดยไม่หยุดชะงักและยังคงวิ่งแข่งกันอยู่ การทำซ้ำครั้งที่สามและครั้งสุดท้ายใช้วิธีการที่อธิบายไว้ข้างต้นและในที่สุดก็อนุญาตให้ฉันสร้างกรอบงาน GUI แบบมัลติเธรดที่แม้แต่คนง่าย ๆ อย่างที่ฉันสามารถทำได้อย่างถูกต้อง
จากนั้นการออกแบบ GUI แบบมัลติเธรดขั้นสุดท้ายนี้ทำให้ฉันสามารถหาสิ่งอื่นที่ง่ายกว่ามากในการให้เหตุผลและหลีกเลี่ยงข้อผิดพลาดประเภทที่ฉันมักจะทำและเหตุผลหนึ่งที่ฉันพบว่าเหตุผลง่ายกว่า อย่างน้อยก็เป็นเพราะลูปที่เป็นเนื้อเดียวกันและวิธีที่พวกเขาคล้ายกับโฟลว์การควบคุมคล้ายกับตอนที่ฉันทำโพลในสมัยดอส (แม้ว่ามันจะไม่ได้ลงคะแนนเลือกตั้งจริงๆ ความคิดคือการย้ายห่างจากโมเดลการจัดการเหตุการณ์มากที่สุดเท่าที่จะเป็นไปได้ซึ่งหมายถึงลูปที่ไม่เป็นเอกเทศผลข้างเคียงที่ไม่เป็นเนื้อเดียวกันการควบคุมกระแสที่ไม่เป็นเอกภาพและทำงานมากขึ้นเรื่อย ๆ และการรวมผลข้างเคียงด้วยวิธีที่ทำให้ง่ายขึ้นเพียงแค่มุ่งเน้นไปที่ "อะไร"