Notes & software courses · Free to learn
Aph's Blog
On this page

async/await & asyncio

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

จัดการงาน I/O จำนวนมากพร้อมกันด้วย async/await — เบาและขยายได้กว่า thread

asyncio เป็นวิธีทำ concurrency สำหรับงาน I/O-bound จำนวนมาก (เช่นยิง API หลายพันตัว) ด้วย event loop ที่สลับงานเมื่อตัวหนึ่งรอ I/O — เบากว่า thread เพราะไม่ต้องสร้าง thread จริงหลายตัว เป็นพื้นฐานของ framework สมัยใหม่อย่าง FastAPI (บท 10)

async def & await

ฟังก์ชัน async (coroutine) ประกาศด้วย async def และใช้ await ตรงจุดที่ "รอ" — ระหว่างรอ event loop ไปทำงานอื่นได้

python
import asyncio

async def fetch(name):
    print(f"เริ่ม {name}")
    await asyncio.sleep(1)      # จำลองรอ I/O (ระหว่างนี้ทำตัวอื่นได้)
    print(f"เสร็จ {name}")
    return name

async def main():
    result = await fetch("A")    # await = รอ coroutine นี้
    print(result)

asyncio.run(main())             # รัน event loop

asyncio.gather — ทำหลายงานพร้อมกัน

พลังจริงของ asyncio คือรันหลาย coroutine พร้อมกัน — gather รอทั้งหมดเสร็จ

python
import asyncio

async def fetch(name):
    await asyncio.sleep(1)
    return f"เสร็จ {name}"

async def main():
    # ยิง 3 งานพร้อมกัน — รวม ~1 วินาที (ไม่ใช่ 3)
    results = await asyncio.gather(
        fetch("A"), fetch("B"), fetch("C")
    )
    print(results)   # ['เสร็จ A', 'เสร็จ B', 'เสร็จ C']

asyncio.run(main())

async vs thread (เลือกยังไง)

  • asyncio: I/O-bound จำนวนมาก ๆ (พัน++), เบา, แต่ต้องใช้ library ที่รองรับ async
  • thread: I/O-bound ไม่เยอะมาก, ใช้กับโค้ด blocking เดิมได้เลย
  • ทั้งคู่ไม่ช่วย CPU-bound (นั่นคืองานของ multiprocessing)
ห้ามเรียก blocking ใน async

ในฟังก์ชัน async อย่าเรียกโค้ด blocking ปกติ (เช่น time.sleep แทน asyncio.sleep, หรือ requests แทน async client) เพราะมันจะบล็อก event loop ทั้งระบบ ทำให้ coroutine อื่นค้างหมด — ต้องใช้เวอร์ชัน async ของ library นั้น

สรุปหัวข้อนี้ & จบบท

  • async def + await: coroutine ที่สลับงานตอนรอ I/O ผ่าน event loop
  • asyncio.run() เริ่ม loop; asyncio.gather() รันหลายงานพร้อมกัน
  • เหมาะ I/O-bound จำนวนมาก เบากว่า thread (FastAPI ใช้ async)
  • ห้ามเรียก blocking ใน async — ใช้เวอร์ชัน async ของ library
แบบฝึกหัด

1) เขียน coroutine ที่ await asyncio.sleep แล้วคืนค่า 2) ใช้ asyncio.gather ยิง 5 งานพร้อมกัน เทียบเวลากับทำทีละตัว 3) อธิบายว่าทำไม asyncio เบากว่า thread 4) อธิบายว่าทำไมห้ามใช้ time.sleep ใน async