PlusMagi's Blog By Pitt Phunsanit Backend Qt Multithreading & Concurrency (การจัดการงานเบื้องหลัง การใช้ QThread, QThreadPool และ QtConcurrent)

Qt Multithreading & Concurrency (การจัดการงานเบื้องหลัง การใช้ QThread, QThreadPool และ QtConcurrent)

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

หัวใจสำคัญของการแก้ไขปัญหานี้คือการทำความเข้าใจแนวคิดเรื่อง Concurrency (ภาวะพร้อมกัน) และ Parallelism (การทำงานขนาน) การทำความเข้าใจแนวคิดเหล่านี้ช่วยให้เราสามารถแยกภาระงานที่ใช้เวลานานออกจาก Main Thread หรือ Connection Thread หลัก เพื่อให้การตอบสนองของระบบยังคงลื่นไหลอยู่เสมอ

💡 หลักการ Concurrency ในบริบทของฐานข้อมูล

แม้ว่า Qt จะเป็น Framework สำหรับ GUI แต่หลักการจัดการงานเบื้องหลัง (Background Processing) นั้นเป็นหลักการสากลที่นำมาปรับใช้ได้กับทุกระบบ รวมถึง PostgreSQL ด้วย เมื่อเราพูดถึง Concurrency ใน PostgreSQL เราไม่ได้หมายถึงการรันโค้ดหลายเธรดในระดับแอปพลิเคชันโดยตรง แต่หมายถึงการออกแบบระบบที่สามารถรับและประมวลผลคำขอ (Requests) จำนวนมากได้อย่างมีประสิทธิภาพ โดยไม่ทำให้ Connection หลักเกิดการติดขัด (Blocking) ซึ่งเป็นหลักการเดียวกับการย้ายงานหนักออกจาก GUI Thread

⚙️ การจำลองการทำงานแบบ Background Worker ใน PostgreSQL

ในเชิงของ PostgreSQL เราสามารถจำลองการทำงานแบบ Asynchronous หรือ Background Worker ได้โดยการใช้ตารางคิว (Job Queue) และฟังก์ชัน (Stored Procedure) เพื่อให้ Processors อื่นๆ เข้ามาดึงงานไปประมวลผลทีหลัง แทนที่จะให้ Connection หลักรอนานจนหมดเวลา (Timeout)

SQL

-- 1. สร้างตารางคิวสำหรับเก็บงานที่ต้องประมวลผลเบื้องหลัง (Job Queue) --------------------------------------------------------------------------------- 
CREATE TABLE background_jobs (
    job_id SERIAL PRIMARY KEY,
    data TEXT NOT NULL, -- ข้อมูลที่ต้องใช้ในการประมวลผล เช่น 'apple,banana,orange'
    status VARCHAR(20) DEFAULT 'PENDING', 
    created_at TIMESTAMP DEFAULT NOW()
);

-- 2. สร้างฟังก์ชัน Worker ที่ทำหน้าที่ประมวลผลงาน (จำลองการทำงานที่ใช้เวลานาน) --------------------------------------------------------------------------------- 
CREATE OR REPLACE FUNCTION process_job(p_job_id INT) RETURNS TEXT AS $$
BEGIN
    -- จำลองการคำนวณที่กินเวลานาน (แทนการทำงานของ QThread)
    PERFORM pg_sleep(0.5);
    
    -- อัปเดตสถานะงานเมื่อเสร็จสิ้น
    UPDATE background_jobs SET status = 'COMPLETED' WHERE job_id = p_job_id;
    
    RETURN 'Job ' || p_job_id || ' processed successfully.';
END; 
$$ LANGUAGE plpgsql;

-- 3. การส่งงานเข้าคิว (Enqueueing the job) --------------------------------------------------------------------------------- 
INSERT INTO background_jobs (data) VALUES ('1,2,3');

-- 4. การเรียกใช้ Worker (จำลองการเรียกใช้ QThreadPool) 
SELECT process_job(1);

✅ สรุปแนวคิดในการออกแบบระบบ

การออกแบบระบบที่คำนึงถึง Concurrency ไม่ได้หมายถึงการใช้เธรดจำนวนมาก แต่หมายถึงการออกแบบที่ ไม่บล็อก (Non-blocking) การทำงานหลักควรเป็นเพียงการบันทึกงานเข้าคิว (Insert into `background_jobs`) และปล่อยให้ Processors หรือ Worker อื่นๆ เข้ามาจัดการงานเหล่านั้นในภายหลัง ด้วยการใช้รูปแบบ Job Queue นี้ ทำให้ระบบหลักสามารถตอบสนองต่อผู้ใช้ได้ทันที แม้ว่างานเบื้องหลังจะใช้เวลาประมวลผลนานเพียงใดก็ตาม