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

Multiprocessing

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

ข้ามข้อจำกัด GIL ด้วยการแยกเป็นหลาย process — สำหรับงานคำนวณหนัก (CPU-bound)

เมื่องานเป็น CPU-bound (คำนวณหนัก) thread ช่วยไม่ได้เพราะ GIL ทางออกคือ multiprocessing — แยกเป็นหลาย process ที่แต่ละตัวมี Python interpreter ของตัวเอง (มี GIL ของตัวเอง) จึงรันพร้อมกันจริงบนหลาย core

ProcessPoolExecutor

ใช้คล้าย ThreadPoolExecutor แต่เป็น process — เหมาะกับงานคำนวณหนักที่แบ่งเป็นชิ้นได้

python
from concurrent.futures import ProcessPoolExecutor

def heavy_compute(n):
    # งาน CPU-bound: คำนวณหนัก
    return sum(i * i for i in range(n))

if __name__ == "__main__":      # จำเป็นสำหรับ multiprocessing
    tasks = [10_000_000] * 4
    with ProcessPoolExecutor() as executor:
        results = list(executor.map(heavy_compute, tasks))
    print(results)
    # ใช้หลาย core พร้อมกันจริง เร็วกว่าทำทีละตัว
ต้องมี if __name__ == "__main__"

multiprocessing ต้องอยู่ใต้ guard if __name__ == "__main__": (จากบท 4) ไม่งั้นบางระบบจะสร้าง process ซ้อนไม่รู้จบ — เป็นกับดักที่เจอบ่อยกับมือใหม่

thread vs process — ต้นทุน

threadprocess
memoryแชร์กัน (เบา)แยกกัน (หนัก)
ข้าม GILไม่ได้ได้ (พร้อมกันจริง)
เหมาะกับI/O-boundCPU-bound
ต้นทุนสร้างต่ำสูง
process หนักกว่า thread

การสร้าง process มีต้นทุนสูงกว่า thread (แยก memory, ส่งข้อมูลข้าม process ต้อง serialize) — ใช้กับงานคำนวณหนักจริง ๆ ที่คุ้มค่า ไม่ใช่งานเล็ก ๆ

สรุปหัวข้อนี้

  • multiprocessing แยกเป็นหลาย process ข้าม GIL → รันพร้อมกันจริง
  • เหมาะกับ CPU-bound; ใช้ ProcessPoolExecutor คล้าย thread pool
  • ต้องมี if __name__ == "__main__" guard
  • process หนักกว่า thread (memory แยก, ต้นทุนสูง) — ใช้เมื่อคุ้ม
แบบฝึกหัด

1) ใช้ ProcessPoolExecutor เร่งงานคำนวณหนักหลายชิ้น เทียบเวลากับแบบลำดับ 2) ลองงานเดียวกันด้วย thread แล้วเทียบ (จะเห็นว่า process เร็วกว่าสำหรับ CPU-bound) 3) อธิบายว่าทำไม process ข้าม GIL ได้ 4) บอกข้อเสียของ process เทียบ thread