IO แบบอะซิงโครนัสด้วย epoll และ kqueue
รองรับการเชื่อมต่อจำนวนมากด้วย epoll บน Linux และ kqueue บน BSD หรือ macOS
IO แบบอะซิงโครนัสด้วย epoll และ kqueue เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C++ Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงใช้ I/O แบบอะซิงโครนัส
การใช้เธรดหนึ่งเธรดต่อการเชื่อมต่อไม่สามารถรองรับไคลเอ็นต์หลายพันหรือหลายล้านรายได้ดี I/O แบบอะซิงโครนัสทำให้เธรดเดียวจัดการซ็อกเก็ตจำนวนมากได้ โดยรอให้ซ็อกเก็ตใดก็ตามพร้อมอ่านหรือพร้อมเขียน
Linux: epoll
Linux มีส่วนติดต่อเหตุการณ์ที่ปรับขนาดได้ เพิ่มตัวระบุไฟล์ลงในอินสแตนซ์ของ epoll แล้วรอเหตุการณ์จากตัวระบุใดก็ตาม
#include <sys/epoll.h>
int epfd = epoll_create1(0);
epoll_event ev{};
ev.events = EPOLLIN;
ev.data.fd = sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);การรอเหตุการณ์
epoll_wait จะบล็อกจนกว่าจะมีเหตุการณ์ จากนั้นส่งคืนตัวระบุที่พร้อมทำงาน
epoll_event events[64];
int n = epoll_wait(epfd, events, 64, -1);
for (int i = 0; i < n; ++i) {
int fd = events[i].data.fd;
handle_io(fd);
}แบบทำงานเมื่อระดับเปลี่ยนเทียบกับแบบทำงานเมื่อขอบเปลี่ยน
มีสองโหมด:
- แบบทำงานเมื่อระดับเปลี่ยน (ค่าเริ่มต้น) — epoll ยังคงรายงานตราบใดที่เงื่อนไขยังเป็นจริง
- แบบทำงานเมื่อขอบเปลี่ยน (
EPOLLET) — รายงานเฉพาะเมื่อสถานะเปลี่ยน คุณต้องอ่านข้อมูลจากซ็อกเก็ตจนหมดทุกครั้ง
macOS และ BSD: kqueue
kqueue เป็นสิ่งเทียบเท่า epoll ของ BSD และมีให้ใช้บน macOS ด้วย แนวคิดคล้ายกัน แต่ส่วนติดต่อแตกต่างกัน
#include <sys/event.h>
int kq = kqueue();
struct kevent ev;
EV_SET(&ev, sock, EVFILT_READ, EV_ADD, 0, 0, nullptr);
kevent(kq, &ev, 1, nullptr, 0, nullptr);Windows: IOCP
Windows ใช้พอร์ตเสร็จสิ้นการทำงานของ I/O (IOCP) ซึ่งเป็นแบบจำลองที่อิงการเสร็จสิ้น (แจ้งเตือนเมื่อเสร็จแล้ว) แทนแบบจำลองความพร้อมของ epoll/kqueue
ซ็อกเก็ตแบบไม่บล็อก
ตั้งค่าซ็อกเก็ตให้ไม่บล็อกด้วย fcntl(fd, F_SETFL, O_NONBLOCK) มิฉะนั้นการอ่านและการเขียนอาจบล็อกลูปเหตุการณ์ทั้งหมด
รูปแบบลูปเหตุการณ์
ลูปที่ทำงานตลอดไป:
- รอเหตุการณ์ที่พร้อมทำงาน
- สำหรับแต่ละเหตุการณ์ ให้ทำ I/O จนกว่าการทำงานจะบล็อก
- ทำซ้ำ
การจัดการไคลเอ็นต์จำนวนมาก
เธรด epoll เดียวสามารถจัดการการเชื่อมต่อพร้อมกันได้หลายหมื่นรายการ ซึ่งเป็นปัญหา C10K ระบบสมัยใหม่รองรับได้ถึงหลายล้านรายการ
ข้อผิดพลาดที่พบบ่อย
โปรดระวัง:
- ลืมตั้งโหมดไม่บล็อก
- ใช้แบบทำงานเมื่อขอบเปลี่ยนโดยไม่อ่านข้อมูลจากซ็อกเก็ตจนหมด
- ไม่ลบตัวระบุไฟล์ที่ปิดแล้วออกจากชุด epoll
- บัฟเฟอร์รั่วไหลต่อการเชื่อมต่อ
ตัวห่อหุ้มระดับสูง
การเขียนลูป epoll ด้วยตนเองมีโอกาสเกิดข้อผิดพลาดสูง สำหรับโค้ดใช้งานจริงให้ใช้ libuv, libevent หรือ Boost.Asio ซึ่งซ่อนความแตกต่างระหว่างแพลตฟอร์มและมีลูป I/O ที่ผ่านการทดสอบแล้ว
อะซิงโครนัสเทียบกับเธรด
I/O แบบอะซิงโครนัสรองรับการขยายขนาดได้ดีกว่า แต่เขียนได้ยากกว่า สำหรับเซิร์ฟเวอร์ที่มีการเชื่อมต่อระดับหลักพัน การใช้เธรดต่อการเชื่อมต่อจะเรียบง่ายกว่า ให้เลือกตามปริมาณงานที่คาดว่าจะเกิดขึ้น
ตรวจสอบอย่างรวดเร็ว
โหมดแบบทำงานเมื่อขอบเปลี่ยนและแบบทำงานเมื่อระดับเปลี่ยนใน epoll แตกต่างกันอย่างไร
สรุปทบทวน
I/O แบบอะซิงโครนัสรองรับการทำงานพร้อมกันจำนวนมหาศาลได้ด้วยการจัดการซ็อกเก็ตจำนวนมากในเธรดเดียว Linux ใช้ epoll, BSD/macOS ใช้ kqueue และ Windows ใช้ IOCP ตั้งค่าซ็อกเก็ตให้ไม่บล็อก สำหรับการใช้งานจริง ให้ใช้ไลบรารี (Asio, libuv, libevent) แทนการเขียนลูปเหตุการณ์ด้วยตนเอง
คำถามที่พบบ่อย
บทเรียน “IO แบบอะซิงโครนัสด้วย epoll และ kqueue” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “IO แบบอะซิงโครนัสด้วย epoll และ kqueue” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “IO แบบอะซิงโครนัสด้วย epoll และ kqueue”
รองรับการเชื่อมต่อจำนวนมากด้วย epoll บน Linux และ kqueue บน BSD หรือ macOS คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “IO แบบอะซิงโครนัสด้วย epoll และ kqueue” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม
ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- API ซ็อกเก็ต BSD ใน C++
- การสร้างเซิร์ฟเวอร์สะท้อน TCP
- IO แบบอะซิงโครนัสด้วย epoll และ kqueue
- การใช้ Boost Asio สำหรับ IO แบบอะซิงโครนัสสมัยใหม่