วัน: 25 มิถุนายน 2019

python: Concurrency & Asynchronous Programming (การประมวลผลแบบขนานด้วย Threading, Multiprocessing และ Asyncio)python: Concurrency & Asynchronous Programming (การประมวลผลแบบขนานด้วย Threading, Multiprocessing และ Asyncio)

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


เจาะลึกรายละเอียดและประเด็นสำคัญ

หัวใจของการจัดการงานที่ต้องรอคอยคือการทำความเข้าใจว่าเรากำลังเผชิญกับภาระงานประเภทใด ภาระงานจะแบ่งออกเป็นสองกลุ่มหลัก คือ I/O-bound tasks (งานที่ใช้เวลาส่วนใหญ่ในการรอ Input/Output เช่น การเรียกเครือข่าย) และ CPU-bound tasks (งานที่ใช้พลังการประมวลผลของ CPU อย่างหนัก เช่น การคำนวณทางคณิตศาสตร์ซับซ้อน) การเลือกเครื่องมือให้เหมาะสมจึงเป็นสิ่งสำคัญอย่างยิ่ง

Python มีกลไกในการจัดการงานเหล่านี้ที่หลากหลาย ตั้งแต่ threading สำหรับการทำงานแบบขนานเบาๆ (เหมาะกับ I/O-bound) ไปจนถึง multiprocessing ที่สร้าง Process แยกเพื่อหลีกเลี่ยงข้อจำกัดของ Global Interpreter Lock (GIL) และสุดท้ายคือ asyncio ซึ่งเป็นแนวคิดเชิง Asynchronous Programming ที่ใช้ Event Loop ในการจัดการงานที่ต้องรอคอยอย่างมีประสิทธิภาพสูงสุด ทำให้สามารถจัดการ Connection จำนวนมากได้ด้วยทรัพยากรที่น้อยกว่า

import asyncio
import time

async def fetch_data(delay, name):
    print(f"[{name}] เริ่มการดึงข้อมูล...")
    await asyncio.sleep(delay) # จำลองการรอ I/O
    print(f"[{name}] ดึงข้อมูลเสร็จสิ้น.")
    return f"{name} Data"

async def main():
    start_time = time.time()
    # สร้างงานหลายอย่างพร้อมกัน (Concurrency)
    tasks = [fetch_data(i, f"Task {i}") for i in range(3)]
    results = await asyncio.gather(*tasks)
    end_time = time.time()
    print("\n--- ผลลัพธ์ทั้งหมด ---")
    for result in results:
        print(result)
    print(f"\nรวมเวลาที่ใช้: {end_time - start_time:.2f} วินาที (ทำงานพร้อมกัน)")

if __name__ == "__main__":
    asyncio.run(main())


การนำไปประยุกต์ใช้ในชีวิตและการทำงานยุคใหม่

  • Web Scraping และ API Client (I/O Bound):
  • การประมวลผลข้อมูลขนาดใหญ่ (CPU Bound):

ในการพัฒนา Backend Service ที่ต้องรับมือกับผู้ใช้งานจำนวนมากพร้อมกัน การเข้าใจความแตกต่างระหว่าง Concurrency และ Parallelism รวมถึงการเลือกใช้ asyncio สำหรับงาน I/O หรือ multiprocessing สำหรับงานคำนวณหนัก จะเป็นกุญแจสำคัญที่ทำให้ระบบของคุณมีความเสถียร ขยายขนาดได้ (Scalable) และตอบสนองได้อย่างรวดเร็วในระดับ Production


อ่านเพิ่มเติม