อ่าน 4 นาที
ลูปเหตุการณ์
ใน ซอฟต์แวร์ ลู ปเหตุการณ์ (event loop) คือ อัลกอริทึม ที่ส่งคำสั่ง ควบคุมการทำงาน ไปยัง เหตุการณ์ต่างๆ อย่างต่อเนื่อง ลูปจะร้องขอเหตุการณ์ถัดไปจากผู้ให้บริการเหตุการณ์ (event...
ลูปเหตุการณ์
ในซอฟต์แวร์ลูปเหตุการณ์ (event loop)คืออัลกอริทึมที่ส่งคำสั่งควบคุมการทำงานไปยังเหตุการณ์ต่างๆ อย่างต่อเนื่อง ลูปจะร้องขอเหตุการณ์ถัดไปจากผู้ให้บริการเหตุการณ์ (event provider) (ซึ่งโดยทั่วไปจะบล็อกลูปจนกว่าจะมีเหตุการณ์เกิดขึ้น) และเมื่อได้รับเหตุการณ์แล้ว จะเรียกใช้ตัวจัดการเหตุการณ์ (event handler ) ที่เกี่ยวข้อง เมื่อลูปเหตุการณ์เป็นตัวส่งคำสั่งเหตุการณ์หลักของโปรแกรมซึ่งมักจะเป็นเช่นนั้น เราจะเรียกว่าลูปหลัก (main loop ) หรือลูปเหตุการณ์หลัก (main event loop )
ในสภาพแวดล้อมสมัยใหม่ เช่น เว็บเบราว์เซอร์และรันไทม์เซิร์ฟเวอร์ อีเวนต์ลูปเป็นกลไกพื้นฐานที่ช่วยให้การทำงานแบบอะซิงโครนัสเกิดขึ้นได้โดยการตรวจสอบและส่งอีเวนต์หรือข้อความจากคิวอย่างต่อเนื่องเมื่อเธรดโปรแกรมหลักไม่ได้ทำงาน ใน JavaScript อีเวนต์ลูปช่วยให้สามารถจัดการงานต่างๆ ได้โดยไม่บล็อก เช่น การโต้ตอบกับผู้ใช้ ตัวจับเวลา และการดำเนินการ I/O แม้ว่าภาษาจะเป็นแบบเธรดเดียวก็ตาม[ 1 ]
อัลกอริทึมเดียวกันนี้สามารถใช้ในการประมวลผลข้อความ ขาเข้า ซึ่งเป็นกลุ่มของเหตุการณ์ได้ ในบริบทนี้ อัลกอริทึมดังกล่าวเรียกว่า ลู ปข้อความตัวจัดการข้อความหรือปั๊มข้อความการใช้งานทั่วไปของลูปข้อความคือการสื่อสารระหว่างกระบวนการโดยการส่งข้อความ ซึ่งคิวข้อความจะถูกจัดการอยู่นอกโปรแกรม (เช่น โดยระบบปฏิบัติการ )
โดยทั่วไป โปรแกรมที่ทำงานใน สภาพแวดล้อม ส่วนติดต่อผู้ใช้แบบกราฟิก (GUI) จะใช้ลูปเหตุการณ์ และเนื่องจากสภาพแวดล้อม GUI เป็นที่แพร่หลาย แอปพลิเคชันสมัยใหม่ส่วนใหญ่จึงมีลูปเหตุการณ์หลัก
ในรหัสเทียมต่อไปนี้get_next_message()เป็นตัวแทนสำหรับฟังก์ชันที่โดยทั่วไปแล้วระบบปฏิบัติการจะจัดเตรียมไว้ให้ ซึ่งจะบล็อกจนกว่าจะมีข้อความพร้อมใช้งาน ดังนั้นลูปจะทำงานซ้ำเฉพาะเมื่อมีข้อความให้ประมวลผลเท่านั้น
วนซ้ำ ข้อความ := รับข้อความถัดไป() ประมวลผลข้อความ (ข้อความ) ในขณะที่ข้อความไม่เท่ากับ "ออกจากระบบ"
ทางเลือกอื่นๆ
โปรแกรมจำนวนมากมีการออกแบบลูปเหตุการณ์ในระดับสูง โดยเฉพาะลูปเหตุการณ์หลัก แต่ก็ยังมีรูปแบบการออกแบบอื่นๆ อีกด้วย
โปรแกรมสามารถปิดตัวลงได้ทันทีเมื่อทำงานที่ได้รับมอบหมายเสร็จสิ้นโดยไม่ต้องมีการโต้ตอบจากภายนอก (เช่นผู้ใช้ ) บ่อยครั้งที่โปรแกรมดังกล่าวมีพฤติกรรมเสริมที่ตั้งค่าไว้ก่อนที่โปรแกรมจะเริ่มทำงาน เช่น ผ่านทางอินเทอร์เฟซบรรทัดคำสั่ง (CLI) หรือตัวแปรสภาพแวดล้อมซอฟต์แวร์ยูทิลิตี้ ส่วนใหญ่ มักเป็นประเภทนี้
แม้ว่าโปรแกรมจะมีการโต้ตอบกับผู้ใช้ แต่ก็อาจไม่ได้ใช้ลูปเหตุการณ์ โปรแกรมที่มี CLI ภายในนั้นจะมีตัวประมวลผลคำสั่งที่คล้ายกับลูปเหตุการณ์ตรงที่มันจะส่งต่อไปยังตัวจัดการคำสั่งตามข้อมูลที่ผู้ใช้ป้อนเข้ามา
ตัวอย่าง
เอชไอวี/เจวาสคริปต์
โดยทั่วไปแล้ว เว็บเพจและ JavaScript จะทำงานใน กระบวนการ เบราว์เซอร์ แบบ เธรด เดียว กระบวนการเบราว์เซอร์จะจัดการกับข้อความจากคิวทีละข้อความ ฟังก์ชัน JavaScript หรือเหตุการณ์อื่นๆ ของเบราว์เซอร์อาจเชื่อมโยงกับข้อความนั้นๆ เมื่อกระบวนการเบราว์เซอร์ประมวลผลข้อความเสร็จแล้ว ก็จะดำเนินการต่อไปยังข้อความถัดไปในคิว
ในสภาพแวดล้อม JavaScript ลูปเหตุการณ์จะทำงานร่วมกับคิวแยกต่างหาก ซึ่งรวมถึงคิวงานและคิวงานย่อย เพื่อจัดการการทำงานแบบอะซิงโครนัส เช่น ตัวจับเวลา การเรียกกลับของ Promise และเหตุการณ์ DOM เมื่อสแต็กการเรียกว่างเปล่า ลูปเหตุการณ์จะเลือกงานถัดไปจากคิวเหล่านี้เพื่อดำเนินการ[ 2 ]
แอปพลิเคชัน Windows
ใน ระบบปฏิบัติการ Windowsกระบวนการที่โต้ตอบกับผู้ใช้จะต้องยอมรับและตอบสนองต่อข้อความที่เข้ามา ซึ่งโดยส่วนใหญ่แล้วจะทำผ่านลูปข้อความในกระบวนการนั้น ใน Windows ข้อความเทียบเท่ากับเหตุการณ์ที่ถูกสร้างขึ้นและกำหนดให้กับระบบปฏิบัติการ เหตุการณ์อาจเป็นการโต้ตอบของผู้ใช้ การรับส่งข้อมูลเครือข่าย การประมวลผลของระบบ กิจกรรมของตัวจับเวลา การสื่อสารระหว่างกระบวนการ และอื่นๆ สำหรับเหตุการณ์ที่ไม่โต้ตอบและเป็นเพียงการรับส่งข้อมูล (I/O) เท่านั้น Windows มีพอร์ตการเสร็จสิ้นการรับ ส่ง ข้อมูล (I/O completion ports) ลูปของพอร์ตการเสร็จสิ้นการรับส่งข้อมูลจะทำงานแยกต่างหากจากลูปข้อความ และจะไม่โต้ตอบกับลูปข้อความโดยอัตโนมัติ
หัวใจหลักของแอปพลิเคชันWin32 ส่วนใหญ่ คือ ฟังก์ชัน WinMain()ซึ่งเรียกGetMessage()ในลูป GetMessage() จะบล็อกจนกว่าจะได้รับข้อความ (เหตุการณ์) (โดยมีฟังก์ชันPeekMessage()เป็นทางเลือกที่ไม่บล็อก) หลังจากประมวลผลเพิ่มเติมแล้ว จะเรียกDispatchMessage()ซึ่งจะส่งข้อความไปยังตัวจัดการที่เกี่ยวข้อง หรือที่เรียกว่าWindowProcโดยปกติแล้ว ข้อความที่ไม่มีWindowProc() พิเศษ จะถูกส่งไปยังDefWindowProcซึ่งเป็นค่าเริ่มต้น DispatchMessage() จะเรียก WindowProc ของแฮนเดิล HWNDของข้อความ (ที่ลงทะเบียนไว้ด้วย ฟังก์ชัน RegisterClass() )
ระบบปฏิบัติการ Windows รุ่นใหม่กว่ารับประกันว่าข้อความจะถูกส่งไปยังลูปข้อความของแอปพลิเคชันตามลำดับที่ระบบและอุปกรณ์ต่อพ่วงรับรู้ การรับประกันนี้มีความสำคัญอย่างยิ่งเมื่อพิจารณาถึงผลที่ตามมาของการออกแบบ แอปพลิเคชัน แบบมัลติเธรดอย่างไรก็ตาม ข้อความบางข้อความมีกฎที่แตกต่างกัน เช่น ข้อความที่ได้รับเป็นลำดับสุดท้ายเสมอ หรือข้อความที่มีลำดับความสำคัญที่ระบุไว้แตกต่างกัน[ 3 ]
ลูปเหตุการณ์ Xlib
แอปพลิเคชัน Xที่ใช้Xlibโดยตรงนั้นสร้างขึ้นจากXNextEventตระกูลฟังก์ชัน ซึ่งXNextEventจะบล็อกการทำงานจนกว่าจะมีเหตุการณ์ปรากฏในคิวเหตุการณ์ จากนั้นแอปพลิเคชันจะประมวลผลเหตุการณ์นั้นอย่างเหมาะสม ลูปเหตุการณ์ของ Xlib จัดการเฉพาะเหตุการณ์ของระบบหน้าต่างเท่านั้น แอปพลิเคชันที่ต้องการรอไฟล์และอุปกรณ์อื่นๆ อาจสร้างลูปเหตุการณ์ของตนเองจากฟังก์ชันพื้นฐาน เช่นConnectionNumberแต่ในทางปฏิบัติมักจะใช้มัลติเธรดดิ้ง
มีโปรแกรมเพียงไม่กี่โปรแกรม ที่ ใช้ Xlib โดยตรง ในกรณีทั่วไป ชุดเครื่องมือ GUI ที่ใช้ Xlib มักจะรองรับการเพิ่มเหตุการณ์ ตัวอย่างเช่น ชุดเครื่องมือที่ใช้Xt IntrinsicsมีXtAppAddInput()และXtAppAddTimeout()
การเรียกใช้ฟังก์ชัน Xlib จากตัวจัดการสัญญาณนั้นไม่ปลอดภัย เนื่องจากแอปพลิเคชัน X อาจถูกขัดจังหวะในสถานะใดๆ ก็ได้ เช่น ภายในXNextEvent. ดู[1]สำหรับวิธีแก้ปัญหาสำหรับ X11R5, X11R6 และ Xt
ลูปเหตุการณ์ GLib
ลู ปเหตุการณ์ GLibถูกสร้างขึ้นเพื่อใช้ในGTK ในตอนแรก แต่ปัจจุบันใช้ในแอปพลิเคชันที่ไม่ใช่ GUI เช่นD-Bus ด้วยเช่น กัน ทรัพยากรที่ถูกสำรวจคือชุดของตัวอธิบายไฟล์ที่แอปพลิเคชันสนใจ บล็อกการสำรวจจะถูกขัดจังหวะหากมีสัญญาณเข้ามาหรือ หมด เวลา (เช่น หากแอปพลิเคชันระบุการหมดเวลาหรือภารกิจที่ไม่ได้ใช้งาน) แม้ว่า GLib จะมีการสนับสนุนในตัวสำหรับเหตุการณ์ตัวอธิบายไฟล์และการสิ้นสุดของกระบวนการลูก แต่ก็สามารถเพิ่มแหล่งที่มาของเหตุการณ์สำหรับเหตุการณ์ใดๆ ที่สามารถจัดการได้ในรูปแบบเตรียม-ตรวจสอบ-ส่ง[2]
ไลบรารีแอปพลิเคชันที่สร้างขึ้นบนลูปเหตุการณ์ GLib ได้แก่GStreamerและ วิธี การ I/O แบบอะ ซิงโครนัส ของGnomeVFSแต่GTKยังคงเป็นไลบรารีไคลเอ็นต์ที่เห็นได้ชัดเจนที่สุด เหตุการณ์จากระบบหน้าต่าง (ในXซึ่งอ่านจากซ็อกเก็ต X ) จะถูกแปลงโดยGDKให้เป็นเหตุการณ์ GTK และส่งออกมาเป็นสัญญาณ GLib บนออบเจ็กต์วิดเจ็ตของแอปพลิเคชัน
macOS Core Foundation run loops
อนุญาตให้มี CFRunLoop เพียงหนึ่งเดียวต่อเธรด และสามารถแนบแหล่งข้อมูลและผู้สังเกตการณ์ได้ไม่จำกัดจำนวน แหล่งข้อมูลจะสื่อสารกับผู้สังเกตการณ์ผ่านลูปการทำงาน โดยลูปจะจัดการการจัดคิวและการส่งข้อความ
CFRunLoop ถูกแปลงเป็น NSRunLoop ใน Cocoa ซึ่งอนุญาตให้ข้อความใดๆ (เทียบเท่ากับการเรียกฟังก์ชันในรันไทม์ที่ไม่ใช้ การสะท้อนกลับ ) ถูกจัดคิวเพื่อส่งไปยังวัตถุใดๆ ก็ได้
อิงตามไฟล์
ในระบบ Unix แนวคิด ที่ว่าทุกอย่างคือไฟล์นำไปสู่ลูปเหตุการณ์แบบไฟล์ การอ่านและการเขียนไฟล์ การสื่อสารระหว่างกระบวนการ การสื่อสารผ่านเครือข่าย และการควบคุมอุปกรณ์ ล้วนทำได้โดยใช้การอ่าน/เขียนไฟล์ โดยมีเป้าหมายที่ระบุด้วยตัวระบุไฟล์ (file descriptor ) ระบบการเรียก ใช้ selectและpollช่วยให้สามารถตรวจสอบชุดของตัวระบุไฟล์เพื่อดูการเปลี่ยนแปลงสถานะ เช่น เมื่อมีข้อมูลพร้อมให้อ่าน
ตัวอย่างเช่น ลองพิจารณาโปรแกรมที่อ่านข้อมูลจากไฟล์ที่ได้รับการอัปเดตอย่างต่อเนื่องและแสดงเนื้อหาในระบบ X Window Systemซึ่งสื่อสารกับไคลเอนต์ผ่านทางซ็อกเก็ต (ไม่ว่าจะเป็นUnix domainหรือBerkeley ):
def main (): file_fd = open ( "logfile.log" ) x_fd = open_display () construct_interface () while True : rlist , _ , _ = select.select ([ file_fd , x_fd ], [ ] , [ ]): if file_fd in rlist : data = file_fd.read ( ) append_to_display ( data ) send_repaint_message () if x_fd in rlist : process_x_messages ()อิงตามสัญญาณ
ในระบบ Unix สัญญาณคือเหตุการณ์แบบอะซิงโครนัสที่ได้รับการจัดการโดยตัวจัดการสัญญาณซึ่งจะทำงานในขณะที่ส่วนที่เหลือของงานถูกระงับ หากได้รับและจัดการสัญญาณในขณะที่งานกำลังบล็อกอยู่ คำselect()สั่ง select จะส่งคืนค่าก่อนกำหนดด้วยEINTRหากได้รับสัญญาณในขณะที่งานกำลังใช้ CPU อย่างหนักงานจะถูกระงับระหว่างคำสั่งจนกว่าตัวจัดการสัญญาณจะส่งคืนค่า
วิธีหนึ่งในการจัดการสัญญาณคือให้ตัวจัดการสัญญาณตั้งค่าแฟล็กส่วนกลาง และให้ลูปเหตุการณ์ตรวจสอบแฟล็กนั้นทันทีก่อนและหลังselect()การเรียกใช้ฟังก์ชัน หากมีการตั้งค่าแฟล็กไว้ ให้จัดการสัญญาณในลักษณะเดียวกับเหตุการณ์บนตัวระบุไฟล์ อย่างไรก็ตาม วิธีนี้ทำให้เกิดสภาวะการแข่งขัน (race condition ) กล่าวคือ หากมีสัญญาณเข้ามาทันทีระหว่างการตรวจสอบแฟล็กและการเรียกใช้ฟังก์ชัน สัญญาณselect()นั้นจะไม่ได้รับการจัดการจนกว่าselect()จะถึงผลลัพธ์ด้วยเหตุผลอื่น (เช่น ถูกขัดจังหวะโดยผู้ใช้ที่หงุดหงิด)
วิธีแก้ปัญหาที่ POSIXนำมาใช้คือpselect()การเรียก ซึ่งคล้ายกับselect()แต่มีพารามิเตอร์เพิ่มเติมsigmaskที่อธิบายถึงมาสก์สัญญาณวิธีนี้ช่วยให้แอปพลิเคชันสามารถมาสก์สัญญาณในงานหลัก จากนั้นลบมาสก์ออกในช่วงเวลาของselect()การเรียก เพื่อให้ตัวจัดการสัญญาณถูกเรียกเฉพาะเมื่อแอปพลิเคชันอยู่ในสถานะ I/O bound เท่านั้น อย่างไรก็ตาม การใช้งานนั้นpselect()ไม่น่าเชื่อถือเสมอไป เวอร์ชันของ Linux ก่อน 2.6.16 ไม่มีpselect()ระบบการเรียก[ 4 ]ทำให้glibcต้องจำลองผ่านวิธีการที่มีแนวโน้มที่จะเกิด race condition เดียวกันpselect()ซึ่งมีจุดประสงค์เพื่อหลีกเลี่ยง
วิธีแก้ปัญหาทางเลือกที่พกพาสะดวกกว่าคือการแปลงเหตุการณ์แบบอะซิงโครนัสเป็นเหตุการณ์แบบไฟล์โดยใช้เทคนิคself -pipe [ 5 ]โดยที่ "ตัวจัดการสัญญาณจะเขียนไบต์ลงในไปป์ซึ่งปลายอีกด้านจะถูกตรวจสอบโดยselect()โปรแกรมหลัก" [ 6 ]ในเคอร์เนล Linuxเวอร์ชัน 2.6.22 signalfd()มีการเพิ่มการเรียกใช้ระบบใหม่ซึ่งอนุญาตให้รับสัญญาณผ่านตัวอธิบายไฟล์พิเศษ
JavaScript และการประมวลผลแบบอะซิงโครนัส
ในสภาพแวดล้อมเช่นเว็บเบราว์เซอร์และ Node.js ลูปเหตุการณ์เป็นหัวใจสำคัญของพฤติกรรมโปรแกรมแบบอะซิงโครนัส JavaScript ทำงานบนเธรดเดียวสำหรับการดำเนินการ แต่สภาพแวดล้อมโฮสต์มี API สำหรับการดำเนินการที่ไม่บล็อก เช่น ตัวจับเวลา คำขอเครือข่าย และเหตุการณ์ของผู้ใช้ การดำเนินการแบบอะซิงโครนัสที่เสร็จสมบูรณ์จะถูกวางไว้ในคิว และลูปเหตุการณ์จะตรวจสอบซ้ำ ๆ ว่าสแต็กการเรียกว่างหรือไม่เพื่อกำหนดเวลาการเรียกกลับที่อยู่ในคิว ซึ่งทำให้แอปพลิเคชัน JavaScript สามารถตอบสนองได้ในขณะที่จัดการงานแบบอะซิงโครนัสหลายงาน[ 7 ]
ดูเพิ่มเติม
- อินพุต/เอาต์พุตแบบอะซิงโครนัส
- การเขียนโปรแกรมแบบขับเคลื่อนด้วยเหตุการณ์
- เกมลูป
- การสื่อสารระหว่างกระบวนการ
- การส่งข้อความ
ลิงก์ภายนอก
- การเดินทางฝ่าฟันเขาวงกตแห่งการกำหนดเส้นทางข้อความและคำสั่งของ MFC
- การใช้งานข้อความและคิวข้อความ (MSDN)
- การใช้ขั้นตอนการทำงานของ Windows (MSDN)
- WindowProc (MSDN)
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ ลูปเหตุการณ์
ใน ซอฟต์แวร์ ลู ปเหตุการณ์ (event loop) คือ อัลกอริทึม ที่ส่งคำสั่ง ควบคุมการทำงาน ไปยัง เหตุการณ์ต่างๆ อย่างต่อเนื่อง ลูปจะร้องขอเหตุการณ์ถัดไปจากผู้ให้บริการเหตุการณ์ (event...
ทางเลือกอื่นๆ
โปรแกรมจำนวนมากมีการออกแบบลูปเหตุการณ์ในระดับสูง โดยเฉพาะลูปเหตุการณ์หลัก แต่ก็ยังมีรูปแบบการออกแบบอื่นๆ อีกด้วย
เอชไอวี/เจวาสคริปต์
โดยทั่วไปแล้ว เว็บเพจและ JavaScript จะทำงานใน กระบวนการ เบราว์เซอร์ แบบ เธรด เดียว กระบวนการเบราว์เซอร์จะจัดการกับ ข้อความ จาก คิว ทีละ ข้อความ ฟังก์ชัน JavaScript หรือเหตุการณ์อื่นๆ ของเบราว์เซอร์อาจเชื่อมโยงกับข้อความนั้นๆ...
แอปพลิเคชัน Windows
ใน ระบบปฏิบัติการ Windows กระบวนการที่โต้ตอบกับผู้ใช้จะต้องยอมรับและตอบสนองต่อข้อความที่เข้ามา ซึ่งโดยส่วนใหญ่แล้วจะทำผ่าน ลูปข้อความ ในกระบวนการนั้น ใน Windows ข้อความเทียบเท่ากับเหตุการณ์ที่ถูกสร้างขึ้นและกำหนดให้กับระบบปฏิบัติการ...