Async & Concurrency — ภาพรวม
มาจากโลก JavaScript ที่เป็น single-thread
หัวข้อที่มีชื่อว่า “มาจากโลก JavaScript ที่เป็น single-thread”JavaScript ทำงานบน thread เดียว มี call stack เดียว event loop เดียว และไม่มีการแชร์ memory ระหว่าง concurrent units of work เมื่อคุณเขียน async/await ใน Node.js คุณกำลัง schedule microtasks บน thread เดียวนั้น — ไม่มีการทำสองสิ่งพร้อมกันจริงๆ ภายใน process เดียว
Python ให้คุณ เครื่องมือ concurrency สามอย่าง และคุณต้องเลือกให้เหมาะกับงาน:
| เครื่องมือ | คืออะไร | เหมาะกับ |
|---|---|---|
asyncio | Cooperative concurrency แบบ single-threaded | โค้ด I/O-bound async (HTTP, DB, ไฟล์) |
threading | OS threads ที่แชร์ interpreter เดียวกัน | โค้ด I/O-bound, library แบบ blocking เก่า |
multiprocessing | Separate OS processes | งาน CPU-bound ที่ต้องการ parallelism จริงๆ |
Concurrency vs Parallelism
หัวข้อที่มีชื่อว่า “Concurrency vs Parallelism”คำสองคำนี้มักถูกนำมาใช้แทนกัน แต่ความหมายต่างกัน:
- Concurrency — หลาย task อยู่ระหว่างดำเนินการ ในเวลาเดียวกัน แต่ไม่จำเป็นต้อง execute พร้อมกันทุกนาที event loop สลับระหว่าง task เมื่อ task หนึ่งกำลังรอ นี่คือวิธีที่ Node.js ทำงาน และวิธีที่
asyncioของ Python ทำงาน - Parallelism — หลาย task execute พร้อมกันทุกขณะบน CPU core ต่างกัน สิ่งนี้ต้องการหลาย OS process ใน Python (หรือหลาย thread ในภาษาอื่นๆ ส่วนใหญ่)
// JavaScript/Node.js// Concurrency via the event loop — single thread, never truly parallelasync function fetchUser(id: number): Promise<User> { // While this awaits, other promises can run return await db.query("SELECT * FROM users WHERE id = $1", [id]);}
// Promise.all is concurrent, not parallel — still one threadconst [user, posts] = await Promise.all([ fetchUser(1), fetchPosts(1),]);# Python# asyncio — same single-threaded cooperative model as JSimport asyncio
async def fetch_user(user_id: int) -> dict: # While this awaits, other coroutines can run await asyncio.sleep(0) # yield to event loop return {"id": user_id}
# asyncio.gather — same idea as Promise.allasync def main() -> None: user, posts = await asyncio.gather( fetch_user(1), fetch_posts(1), )ภาพรวมทั้งสามชั้น
หัวข้อที่มีชื่อว่า “ภาพรวมทั้งสามชั้น”// JavaScript has one model: event loop + Web Workers for threads// One thread for JS logic, workers for CPU work (separate memory)
// Main threadconst worker = new Worker("worker.js");worker.postMessage({ data: bigArray });worker.onmessage = (e) => console.log(e.data);# Python has three modelsimport asyncio # like Node's event loopimport threading # OS threads (limited by GIL — see below)import multiprocessing # true parallelism, separate memory
# Pick based on your bottleneck:# waiting on network/disk → asyncio or threading# heavy CPU math → multiprocessingควรเลือกเครื่องมือไหน?
หัวข้อที่มีชื่อว่า “ควรเลือกเครื่องมือไหน?”flowchart TD
io{"Bottleneck is waiting on I/O? (network, disk, DB)"}
cpu{"Bottleneck is CPU computation? (math, image, ML)"}
simple{"Just want a simple high-level API?"}
io -- Yes --> asyncio["Use asyncio (preferred) or threading"]
io -- No --> cpu
cpu -- Yes --> mp["Use multiprocessing (bypasses the GIL)"]
cpu -- No --> simple
simple -- Yes --> cf["Use concurrent.futures (wraps threading and multiprocessing)"] บทเรียนที่เหลือในโมดูลนี้จะครอบคลุมแต่ละเครื่องมืออย่างละเอียด