กลุ่มการ์ดงาน asyncio บนโต๊ะมิ้นต์ มีปุ่มยกเลิกสีอำพันตรงกลาง

Python 3.15: TaskGroup.cancel — ยกเลิกกลุ่มงาน asyncio แบบตรง ๆ

น้องกายEngineering

เคยเขียน TaskGroup แล้วอยากหยุดทั้งกลุ่มเมื่อได้ผลลัพธ์แรก — วิธีเก่าคือโยน exception พิเศษแล้วกลืนตอนออกกลุ่ม ซึ่งอ่านยากครับ

Python 3.15 เพิ่ม TaskGroup.cancel (What’s new) ให้เรียกยกเลิกกลุ่มโดยตรงเมื่อเป้าหมายครบหรือไม่ต้องการงานที่เหลือแล้ว

ตัวอย่างโค้ดบางส่วนจากเอกสาร 3.15 (ยังไม่รันบนอินเทอร์พรีเตอร์ในบทความนี้):

import asyncio

async def race():
    async with asyncio.TaskGroup() as tg:
        t1 = tg.create_task(asyncio.sleep(2, result="slow"))
        t2 = tg.create_task(asyncio.sleep(0.1, result="fast"))
        await asyncio.wait({t1, t2}, return_when=asyncio.FIRST_COMPLETED)
        tg.cancel()  # ยกเลิกงานที่เหลือในกลุ่ม

ก่อนหน้านี้หลายคนสร้าง task ปลอมที่ raise แล้ว suppress — ตอนนี้ API ตั้งใจรองรับ early termination ชัดเจน (John Belmonte, gh-127214)

หมายเหตุ: ยังต้องเข้าใจ cancellation ของ awaitable ลูก — cancel() ของกลุ่มไม่ได้แปลว่า I/O ภายนอกทุกเส้นหยุดทันทีถ้าไม่เช็ก CancelledError

Recap

  • อ่านสรุป TaskGroup.cancel ใน What’s new 3.15
  • รีแฟกเตอร์ทริค “raise เพื่อหยุดกลุ่ม” ให้เป็น tg.cancel() เมื่อขึ้น 3.15
  • ทดสอบว่า cleanup ใน finally ของงานลูกยังทำงาน
  • อย่าใช้ยกเลิกกลุ่มแทนการออกแบบ timeout ที่ชัดเจน