แยกงานเป็น FreeRTOS task แล้วเร็วขึ้นเสมอไหม

แยกงานเป็น FreeRTOS task แล้วเร็วขึ้นเสมอไหม - Image 1
04/10/2025•Admin Team•
ESP32IoTTutorialfreertos

เมื่อโปรแกรมเริ่มมีทั้งอ่านเซนเซอร์ คุยเครือข่าย และวาดหน้าจอ เราอาจเริ่มรู้สึกว่าลูปเดียวจัดทุกอย่างยากขึ้น เพราะงานหนึ่งรออยู่ อีกงานก็อยากทำต่อ จึงเป็นจังหวะที่คำว่าแยก task เริ่มดูน่าสนใจ

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

ก่อนสร้าง task เพิ่ม แอดอยากชวนวาดว่างานใดต้องทำเมื่อไร รออะไร และส่งข้อมูลให้ใคร เพื่อให้การแบ่งหน้าที่ช่วยจัดระบบ มากกว่าการย้ายทุกฟังก์ชันไปอยู่คนละชื่อแล้วต้องตามแก้การแย่งกันภายหลัง

แยกงานจากสิ่งที่ต้องรอและกำหนดเวลา

ลองเริ่มจากหน้าที่แทนชื่อฟังก์ชัน เช่น งานอ่านเซนเซอร์มีรอบของมัน งานเครือข่ายรอการเชื่อมต่อและข้อความ ส่วนหน้าจอใช้ข้อมูลล่าสุดเพื่อวาดตามจังหวะที่เหมาะ งานเหล่านี้อาจแบ่งได้เพราะมีเงื่อนไขรอต่างกัน ไม่ใช่เพียงเพราะไฟล์โค้ดอยู่คนละไฟล์

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

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

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

ทำพร้อมกันได้เท่าไรขึ้นกับระบบที่ใช้

scheduler ช่วยจัดเวลาของ task ที่พร้อมทำงาน แต่จำนวน core และรายละเอียดการทำงานยังขึ้นกับชิปกับการตั้งค่า ไม่ใช่บอร์ดที่ใช้ชื่อ ESP32 ทุกตัวจะมีรูปแบบเดียวกัน และการสร้างหลาย task ก็ไม่ได้เพิ่มกำลังประมวลผลของฮาร์ดแวร์ขึ้นมา

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

การเลือก priority จึงควรมาจากหน้าที่และข้อกำหนดเวลา ไม่ใช่เพิ่มให้ task ที่ดูช้าแล้วหวังว่าจะหายเสมอ เพราะงาน priority สูงที่พร้อมวิ่งตลอดอาจทำให้งานต่ำกว่าไม่ค่อยมีโอกาสทำ จนปัญหาไปปรากฏที่ส่วนอื่นแทน

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

มีข้อมูลร่วมแล้วต้องมีเจ้าของที่ชัด

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

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

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

แนวคิดผู้ผลิตข้อมูล คิวจำกัดขนาด และผู้รับที่มีอัตราประมวลผลจำกัด ต้องตรวจคิวสะสมจริง

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

queue ไม่ได้ทำให้ผู้รับเร็วขึ้นเอง

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

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

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

stack กับการคืนเวลาก็เป็นต้นทุนของแต่ละ task

แต่ละ task ต้องมี stack และส่วนจัดการของมัน จึงควรดูการใช้จริงกับขอบเขตที่เหลือ ไม่กำหนดขนาดเท่ากันทุกงานโดยไม่ได้อ่านรายละเอียด framework โดยเฉพาะหน่วยของ API ที่อาจต่างกันระหว่าง ESP-IDF กับตัวอย่าง FreeRTOS ทั่วไป

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

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

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

สรุป

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

Command Eng Logo
CMD yourNgineers
เลขประจำตัวผู้เสียภาษี0805564000814
บทความ
ติดต่อบริษัท คอมมานด์ เอ็นจ์ จำกัด
81/36 เพอร์เฟค พาร์คบางนาตำบลบางเสาธง อำเภอบางเสาธงจังหวัดสมุทรปราการ 10570
team@commandeng.in.th+66 89 393 5191
Facebook Page | Command EngLine | Command Eng Official
© Copyright 2022-2026 Command Eng Co., Ltd.v1.0.4 · 0d556ab · 2026-11-03 15:23