การสำรวจความคิดเห็นสำหรับเหตุการณ์จะดีกว่าการใช้รูปแบบการสังเกตการณ์เมื่อใด


41

มีสถานการณ์สมมติที่การสำรวจเหตุการณ์จะดีกว่าการใช้รูปแบบผู้สังเกตการณ์หรือไม่ ฉันกลัวที่จะใช้การลงคะแนนเลือกตั้งและจะเริ่มใช้งานได้ก็ต่อเมื่อมีคนให้สถานการณ์สมมติที่ดีแก่ฉัน ทั้งหมดที่ฉันคิดได้ก็คือรูปแบบการสังเกตการณ์นั้นดีกว่าการสำรวจ สรุปสถานการณ์นี้:

คุณกำลังเขียนโปรแกรมจำลองรถ รถยนต์เป็นวัตถุ ทันทีที่รถเปิดคุณต้องการเล่นคลิปเสียง "vroom vroom"

คุณสามารถสร้างแบบจำลองนี้ได้สองวิธี:

การสำรวจ : สำรวจความคิดเห็นของรถยนต์ทุก ๆ วินาทีเพื่อดูว่ามันเปิดอยู่หรือไม่ เมื่อเปิดใช้งานให้เล่นคลิปเสียง

รูปแบบการสังเกตการณ์ : ทำให้รถเป็นหัวเรื่องของรูปแบบการสังเกตการณ์ ให้มันเผยแพร่กิจกรรม "เปิด" ให้ผู้สังเกตการณ์ทุกคนทราบเมื่อเปิดเครื่อง สร้างวัตถุเสียงใหม่ที่รับฟังในรถ มีมันใช้โทรกลับ "กับ" ซึ่งเล่นคลิปเสียง

ในกรณีนี้ฉันคิดว่ารูปแบบการสังเกตการณ์ชนะ ประการแรกการทำโพลนั้นใช้หน่วยประมวลผลมากขึ้น ประการที่สองคลิปเสียงจะไม่ทำงานทันทีที่รถเปิด อาจมีช่องว่างได้สูงสุด 1 วินาทีเนื่องจากช่วงเวลาการสำรวจ


ฉันคิดว่าแทบจะไม่มีสถานการณ์ รูปแบบการสังเกตการณ์เป็นสิ่งที่แมปจริงกับโลกแห่งความจริงและชีวิตจริง ดังนั้นฉันคิดว่าไม่มีสถานการณ์ใดที่จะพิสูจน์ว่าไม่ได้ใช้
Saeed Neamati

คุณกำลังพูดถึงเหตุการณ์ส่วนติดต่อผู้ใช้หรือเหตุการณ์โดยทั่วไป?
ไบรอัน Oakley

3
ตัวอย่างของคุณจะไม่ลบปัญหาการสำรวจ / การสังเกต คุณผ่านมันไปสู่ระดับที่ต่ำกว่า โปรแกรมของคุณยังคงต้องคิดออกว่ารถเปิดอยู่หรือไม่ผ่านกลไกบางอย่าง
Dunk

คำตอบ:


55

ลองนึกภาพคุณต้องการรับการแจ้งเตือนเกี่ยวกับรอบเครื่องยนต์ทุกครั้งเช่นเพื่อแสดงการวัดรอบต่อนาทีไปยังผู้ขับขี่

รูปแบบการสังเกตการณ์: เอ็นจิ้นเผยแพร่เหตุการณ์ "รอบเครื่องยนต์" ให้ผู้สังเกตการณ์ทุกคนในแต่ละรอบ สร้างผู้ฟังที่นับเหตุการณ์และอัพเดตจอแสดงผล RPM

การทำโพล:จอแสดงผล RPM จะถามเครื่องยนต์เป็นระยะ ๆ ว่ามีรอบเครื่องยนต์และอัพเดตจอแสดงผล RPM ตามนั้นหรือไม่

ในกรณีนี้รูปแบบของผู้สังเกตการณ์อาจจะหลวม: รอบเครื่องยนต์เป็นกระบวนการที่มีความถี่สูงและมีลำดับความสำคัญสูงคุณไม่ต้องการหน่วงเวลาหรือหยุดกระบวนการนั้นเพียงเพื่ออัปเดตจอแสดงผล คุณไม่ต้องการที่จะฟาดเธรดพูลด้วยเหตุการณ์วงรอบเครื่องยนต์


PS: ฉันยังใช้รูปแบบการสำรวจบ่อยในการเขียนโปรแกรมแบบกระจาย:

รูปแบบของผู้สังเกตการณ์:กระบวนการ A ส่งข้อความไปยังกระบวนการ B ที่ระบุว่า "ทุกครั้งที่เกิดเหตุการณ์อีส่งข้อความไปยังกระบวนการ A"

รูปแบบการสำรวจ:กระบวนการ A ส่งข้อความไปยังกระบวนการ B เป็นประจำว่า "ถ้าคุณเหตุการณ์อีเกิดขึ้นตั้งแต่ครั้งล่าสุดที่ฉันได้สำรวจความคิดเห็นกรุณาส่งข้อความถึงฉันตอนนี้"

รูปแบบการสำรวจสร้างภาระเครือข่ายอีกเล็กน้อย แต่รูปแบบของผู้สังเกตการณ์ก็มีข้อเสียเช่นกัน:

  • หากกระบวนการ A ขัดข้องจะไม่มีการยกเลิกการสมัครและกระบวนการ B จะพยายามส่งการแจ้งเตือนไปยังนิรันดร์ทั้งหมดเว้นแต่จะสามารถตรวจพบความล้มเหลวของกระบวนการทางไกลได้อย่างน่าเชื่อถือ (ไม่ใช่เรื่องง่ายที่จะทำ)
  • หากเหตุการณ์อีบ่อยมากและ / หรือการแจ้งเตือนมีข้อมูลจำนวนมากดังนั้นกระบวนการ A อาจได้รับการแจ้งเตือนเหตุการณ์มากกว่าที่จะสามารถจัดการได้ ด้วยรูปแบบการสำรวจมันก็สามารถเค้นการสำรวจความคิดเห็น
  • ในรูปแบบของผู้สังเกตการณ์การโหลดสูงอาจทำให้ "ระลอก" ผ่านทั้งระบบ หากคุณใช้การปิดกั้นซ็อกเก็ตระลอกเหล่านี้สามารถไปได้ทั้งสองทาง

1
จุดดี. บางครั้งก็เป็นการสำรวจที่ดีกว่าเช่นกันเพื่อประสิทธิภาพ
Falcon

1
จำนวนผู้สังเกตการณ์ที่คาดหวังก็เป็นข้อพิจารณาเช่นกัน เมื่อคุณคาดว่าจะมีผู้สังเกตการณ์จำนวนมากการอัปเดตพวกเขาทั้งหมดจากการสังเกตอาจกลายเป็นปัญหาคอขวดของประสิทธิภาพการทำงาน ง่ายกว่ามากเพียงแค่เขียนค่าบางแห่งและให้ "ผู้สังเกตการณ์" ตรวจสอบค่านั้นเมื่อพวกเขาต้องการ
Marjan Venema

1
"เว้นแต่ว่าจะสามารถตรวจพบความล้มเหลวของกระบวนการระยะไกลได้อย่างน่าเชื่อถือ (ไม่ใช่เรื่องง่ายที่จะทำ)" ... ยกเว้นโดยการสำรวจ; ดังนั้นการออกแบบที่ดีที่สุดคือการลดการตอบสนอง "ไม่มีอะไรเปลี่ยนแปลง" ให้มากที่สุด +1 คำตอบที่ดี
pdr

2
@Jojo: คุณทำได้ใช่ แต่คุณกำลังวางนโยบายที่ควรอยู่ในหน้าจอลงในตัวนับ RPM บางทีผู้ใช้อาจต้องการแสดง RPM ที่มีความแม่นยำสูงเป็นครั้งคราว
Zan Lynx

2
@JoJo: การเผยแพร่กิจกรรมครบรอบ 100 รายการนั้นเป็นการแฮก ใช้งานได้ดีถ้าความถี่ของเหตุการณ์อยู่ในช่วงที่ถูกต้องเสมอหากการประมวลผลเหตุการณ์ไม่ใช้เวลานานเกินไปสำหรับเอ็นจิ้นหากสมาชิกทั้งหมดต้องการความแม่นยำที่เทียบเท่ากัน และต้องใช้หนึ่งการดำเนินการโมดูลัสต่อ RPM ซึ่ง (สมมติว่าไม่กี่พันรอบต่อนาที) เป็นงานที่มากขึ้นสำหรับ CPU กว่าการดำเนินการสำรวจความคิดเห็นไม่กี่ต่อวินาที
nikie

7

การทำโพลจะดีกว่าถ้ากระบวนการทำโพลรันช้ากว่าสิ่งที่โพลมาก หากคุณกำลังเขียนกิจกรรมไปยังฐานข้อมูลมักจะเป็นการดีกว่าที่จะสำรวจผู้สร้างกิจกรรมทั้งหมดของคุณรวบรวมเหตุการณ์ทั้งหมดที่เกิดขึ้นตั้งแต่การสำรวจครั้งสุดท้ายจากนั้นเขียนเหตุการณ์เหล่านั้นในธุรกรรมเดียว หากคุณพยายามเขียนทุกเหตุการณ์ที่เกิดขึ้นคุณอาจไม่สามารถติดตามได้และในที่สุดจะมีปัญหาเมื่อคิวการป้อนข้อมูลของคุณเต็ม นอกจากนี้ยังมีเหตุผลในระบบกระจายแบบคู่ขนานซึ่งเวลาแฝงอยู่ในระดับสูงหรือการตั้งค่าการเชื่อมต่อและการฉีกขาดมีราคาแพง ฉันพบว่าระบบการลงคะแนนในการเขียนและทำความเข้าใจง่ายขึ้น แต่ในสถานการณ์ส่วนใหญ่ผู้สังเกตการณ์หรือผู้บริโภคที่ขับเคลื่อนด้วยเหตุการณ์ดูเหมือนจะให้ประสิทธิภาพที่ดีกว่า (จากประสบการณ์ของฉัน)


7

การทำโพลนั้นง่ายกว่ามากในการทำงานผ่านเครือข่ายเมื่อการเชื่อมต่ออาจล้มเหลวเซิร์ฟเวอร์อาจทำงานเสร็จ ฯลฯ โปรดจำไว้ว่าเมื่อสิ้นวันที่ซ็อกเก็ต TCP ต้องการข้อความ "Keep-a-live" แบบโพล "มิฉะนั้นเซิร์ฟเวอร์จะถือว่าลูกค้า ได้หายไป

การสำรวจยังดีเมื่อคุณต้องการอัปเดต UI แต่วัตถุต้นแบบเปลี่ยนไปอย่างรวดเร็วมากไม่มีการอัปเดตจุด UI มากกว่าสองสามครั้งต่อวินาทีในแอปส่วนใหญ่

การให้เซิร์ฟเวอร์สามารถตอบสนอง“ ไม่มีการเปลี่ยนแปลง” ในราคาที่ถูกมากและคุณไม่ได้สำรวจความคิดเห็นบ่อยเกินไปและคุณไม่มีโพลล์จำนวน 1,000 รายจากนั้นการสำรวจจะทำงานได้ดีมากในชีวิตจริง

อย่างไรก็ตามในกรณี“ ในหน่วยความจำ ” ฉันเริ่มต้นที่จะใช้รูปแบบการสังเกตการณ์ตามปกติแล้วจะทำงานน้อยที่สุด


5

การโพลมีข้อเสียบางประการโดยทั่วไปคุณระบุไว้แล้วในคำถามของคุณ

อย่างไรก็ตามมันอาจเป็นวิธีที่ดีกว่าเมื่อคุณต้องการแยกแยะสิ่งที่สังเกตได้จากผู้สังเกตการณ์ใด ๆ แต่บางครั้งมันอาจจะเป็นการดีกว่าถ้าใช้ wrapper ที่สังเกตได้เพื่อให้วัตถุนั้นถูกสังเกตในกรณีเช่นนี้

ฉันจะใช้การทำโพลเมื่อสิ่งที่สังเกตได้ไม่สามารถสังเกตได้ด้วยการโต้ตอบกับวัตถุซึ่งมักเป็นกรณีเมื่อทำการสืบค้นฐานข้อมูลเช่นที่คุณไม่สามารถโทรกลับได้ ปัญหาอื่นอาจเป็นแบบมัลติเธรดซึ่งบ่อยครั้งปลอดภัยกว่าในการสำรวจความคิดเห็นและประมวลผลข้อความแทนที่จะเรียกใช้วัตถุโดยตรงเพื่อหลีกเลี่ยงปัญหาที่เกิดขึ้นพร้อมกัน


ฉันไม่แน่ใจว่าทำไมคุณถึงเชื่อว่าการลงคะแนนเลือกตั้งปลอดภัยสำหรับการทำเกลียวหลาย ในกรณีส่วนใหญ่กรณีนี้จะไม่เกิดขึ้น เมื่อตัวจัดการแบบสำรวจความคิดเห็นได้รับคำขอแบบสำรวจความคิดเห็นมันจะต้องคิดออกสถานะของวัตถุที่ถูกสำรวจหากวัตถุที่อยู่ในช่วงกลางของการปรับปรุงแล้วมันจะไม่ปลอดภัยสำหรับตัวจัดการแบบสำรวจความคิดเห็น ในสถานการณ์ของผู้ฟังคุณจะได้รับการแจ้งเตือนเฉพาะเมื่อผู้ยื่นอยู่ในสถานะที่สอดคล้องกันดังนั้นคุณสามารถหลีกเลี่ยงปัญหาการซิงโครไนซ์ส่วนใหญ่ในวัตถุที่สำรวจ
Lie Ryan

4

สำหรับตัวอย่างที่ดีว่าเมื่อหน่วยเลือกตั้งใช้เวลามากกว่าจากการแจ้งเตือนให้ดูที่สแต็กเครือข่ายระบบปฏิบัติการ

มันเป็นเรื่องใหญ่สำหรับ Linux เมื่อเครือข่ายสแต็คเปิดใช้งาน NAPI ซึ่งเป็น API เครือข่ายที่อนุญาตให้ไดรเวอร์เปลี่ยนจากโหมดขัดจังหวะ (การแจ้งเตือน) เป็นโหมดการโพล

ด้วยอินเตอร์เฟซอีเทอร์เน็ตกิกะบิตหลายตัวอินเทอร์รัปต์มักจะโอเวอร์โหลดซีพียูมากเกินไปทำให้ระบบทำงานช้ากว่าที่ควรจะเป็น เมื่อทำการสำรวจการ์ดเครือข่ายจะทำการรวบรวมแพ็คเก็ตเป็นบัฟเฟอร์จนกว่าจะถึงเวลาทำการหรือแม้กระทั่งการเขียนแพ็คเก็ตลงในหน่วยความจำผ่านทาง DMA จากนั้นเมื่อระบบปฏิบัติการพร้อมใช้งานจะทำการสำรวจการ์ดสำหรับข้อมูลทั้งหมดและทำการประมวลผล TCP / IP มาตรฐาน

โหมดการสำรวจอนุญาตให้ CPU รวบรวมข้อมูลอีเธอร์เน็ตในอัตราการประมวลผลสูงสุดโดยไม่ต้องโหลดขัดจังหวะ โหมดอินเตอร์รัปต์อนุญาตให้ CPU ไม่ได้ทำงานระหว่างแพ็กเก็ตเมื่องานไม่ยุ่งมาก

ความลับคือเวลาที่จะเปลี่ยนจากโหมดหนึ่งเป็นโหมดอื่น แต่ละโหมดมีข้อดีและควรใช้ในตำแหน่งที่เหมาะสม


2

ฉันรักการเลือกตั้ง! ฉัน ใช่ ฉัน ใช่ ฉัน ใช่ ฉันยัง ใช่ แล้วตอนนี้ล่ะ? ใช่

ดังที่คนอื่น ๆ พูดถึงมันอาจจะไร้ประสิทธิภาพอย่างไม่น่าเชื่อถ้าคุณโพลเท่านั้นที่จะได้รับสถานะที่ไม่เปลี่ยนแปลงเหมือนเดิมซ้ำไปซ้ำมา นี่เป็นสูตรสำหรับเบิร์นซีพียูและทำให้อายุการใช้งานแบตเตอรี่สั้นลงอย่างเห็นได้ชัดบนอุปกรณ์พกพา แน่นอนว่ามันไม่สิ้นเปลืองหากคุณได้รับสถานะใหม่และมีความหมายทุกครั้งในอัตราที่ไม่เร็วกว่าที่ต้องการ

แต่เหตุผลหลักที่ฉันรักการลงคะแนนเลือกตั้งเป็นเพราะความเรียบง่ายและธรรมชาติที่คาดเดาได้ คุณสามารถติดตามรหัสและดูได้ง่ายว่าจะเกิดอะไรขึ้นเมื่อไรและที่ไหนและในหัวข้อใด ถ้าในทางทฤษฎีเราอาศัยอยู่ในโลกที่การเลือกตั้งเป็นของเสียเพียงเล็กน้อย (แม้ว่าความเป็นจริงจะอยู่ไกลจากมัน) จากนั้นฉันเชื่อว่ามันจะทำให้การจัดการรหัสง่ายขึ้นมาก และนั่นคือประโยชน์ของการสำรวจและการดึงตามที่ฉันเห็นถ้าเราสามารถเพิกเฉยต่อประสิทธิภาพแม้ว่าเราจะไม่ควรในกรณีนี้

เมื่อฉันเริ่มเขียนโปรแกรมในยุค 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 แบบมัลติเธรดขั้นสุดท้ายนี้ทำให้ฉันสามารถหาสิ่งอื่นที่ง่ายกว่ามากในการให้เหตุผลและหลีกเลี่ยงข้อผิดพลาดประเภทที่ฉันมักจะทำและเหตุผลหนึ่งที่ฉันพบว่าเหตุผลง่ายกว่า อย่างน้อยก็เป็นเพราะลูปที่เป็นเนื้อเดียวกันและวิธีที่พวกเขาคล้ายกับโฟลว์การควบคุมคล้ายกับตอนที่ฉันทำโพลในสมัยดอส (แม้ว่ามันจะไม่ได้ลงคะแนนเลือกตั้งจริงๆ ความคิดคือการย้ายห่างจากโมเดลการจัดการเหตุการณ์มากที่สุดเท่าที่จะเป็นไปได้ซึ่งหมายถึงลูปที่ไม่เป็นเอกเทศผลข้างเคียงที่ไม่เป็นเนื้อเดียวกันการควบคุมกระแสที่ไม่เป็นเอกภาพและทำงานมากขึ้นเรื่อย ๆ และการรวมผลข้างเคียงด้วยวิธีที่ทำให้ง่ายขึ้นเพียงแค่มุ่งเน้นไปที่ "อะไร"


1
"ชอบใช้ตัวแปรเงื่อนไขเพื่อแจ้งให้เธรดตื่น"เสียงเหมือนการจัดเรียงตามผู้สังเกตการณ์ไม่ใช่การสำรวจ
Josh Caswell

ฉันพบความแตกต่างที่ลึกซึ้งมาก แต่การแจ้งเตือนเป็นเพียงในรูปแบบของ "มีงานที่ต้องทำ" เพื่อปลุกเธรด ตัวอย่างเช่นรูปแบบของผู้สังเกตการณ์อาจลดขนาดการเรียกพาเรนต์ของการควบคุมพาเรนต์การเรียกลำดับชั้นลงโดยใช้การจัดส่งแบบไดนามิก สิ่งที่จะมีฟังก์ชั่นการปรับขนาดเหตุการณ์ของพวกเขาเรียกทางอ้อมทันที จากนั้นพวกเขาอาจทาสีตัวเองทันที จากนั้นถ้าเราใช้คิวเหตุการณ์การปรับขนาดการควบคุมหลักอาจผลักดันการปรับขนาดเหตุการณ์ลงตามลำดับชั้นซึ่งจุดที่ฟังก์ชั่นการปรับขนาดสำหรับการควบคุมแต่ละครั้งอาจถูกเรียกในแบบเลื่อนเวลาออกไป ...

... ชี้ไปที่พวกเขาอาจจะผลักดันเหตุการณ์ทาสีใหม่เช่นกันถูกเรียกในแบบรอการตัดบัญชีหลังจากที่ทุกอย่างเสร็จสิ้นการปรับขนาดและทั้งหมดมาจากหัวข้อการจัดการเหตุการณ์กลาง และฉันพบว่าการรวมศูนย์นั้นมีประโยชน์อย่างน้อยก็แค่การดีบั๊กและความสามารถในการหาสาเหตุว่าการประมวลผลนั้นเกิดขึ้นที่ใด (รวมถึงเธรดใด) ... โซลูชันเหล่านี้ ...

มันจะเป็นตัวอย่างเช่นมีLayoutSystemซึ่งเป็นปกตินอนหลับ LayoutSystemแต่เมื่อผู้ใช้ปรับขนาดการควบคุมก็จะใช้ตัวแปรสภาพที่จะตื่นขึ้นมา จากนั้นLayoutSystemปรับขนาดการควบคุมทั้งหมดที่จำเป็นและกลับไปที่โหมดสลีป ในกระบวนการขอบเขตสี่เหลี่ยมที่วิดเจ็ตอยู่นั้นถูกทำเครื่องหมายว่าต้องการการอัพเดต ณ จุดที่PaintSystemตื่นขึ้นมาและผ่านบริเวณที่เป็นสี่เหลี่ยมเหล่านั้นทาสีอีกอันที่ต้องวาดใหม่ในลูปตามลำดับแบบแบน

ดังนั้นตัวแปรเงื่อนไขจะทำตามรูปแบบของผู้สังเกตการณ์เพื่อแจ้งให้เธรดตื่น แต่เราไม่ได้ส่งข้อมูลใด ๆ มากกว่า "มีงานที่ต้องทำ" และแต่ละระบบที่ตื่นขึ้นนั้นอุทิศให้กับการประมวลผลสิ่งต่าง ๆ ในการวนรอบอย่างง่าย ๆ โดยใช้งานที่เป็นเนื้อเดียวกันมากเมื่อเทียบกับคิวเหตุการณ์ที่มีภารกิจที่ไม่เหมือนกัน

-4

ฉันจะให้ภาพรวมเพิ่มเติมเกี่ยวกับวิธีคิดในเรื่องของผู้สังเกตการณ์ คิดเกี่ยวกับสถานการณ์เช่นสมัครรับข้อมูลช่อง YouTube มีจำนวนผู้ใช้ที่สมัครรับข้อมูลจากช่องและเมื่อมีการอัปเดตใด ๆ ในช่องซึ่งประกอบด้วยวิดีโอจำนวนมากผู้ใช้บริการจะได้รับแจ้งว่ามีการเปลี่ยนแปลงในช่องนี้โดยเฉพาะ ดังนั้นเราจึงสรุปได้ว่าหากช่องนั้นเป็น SUBJECT ที่มีความสามารถในการสมัครยกเลิกการสมัครและแจ้ง OBSERVER ทั้งหมดที่ลงทะเบียนในช่องนั้น


2
สิ่งนี้ไม่แม้แต่จะพยายามตอบคำถามที่ถามเมื่อการสำรวจเหตุการณ์จะดีกว่าการใช้รูปแบบผู้สังเกตการณ์ ดูวิธีการตอบ
gnat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.