Python as_completed: เก็บผลงานขนานทีละชิ้นตามลำดับเสร็จ
น้องกายEngineering
ยิงงานขนานแล้วต้องรอตัวช้าสุดทุกครั้งใช่ไหมครับ — ในไลบรารีมาตรฐานมี concurrent.futures.as_completed ที่คืน future ตามลำดับเสร็จ ไม่ใช่ลำดับส่ง
จุดที่ใช้บ่อย:
- แสดงความคืบหน้า / เขียนล็อกทันทีที่งานใดงานหนึ่งจบ
- ยกเลิกงานที่เหลือเมื่อเจอผลที่ “พอแล้ว” (เช่น ค้นหาเจอตัวแรกที่ผ่านเกณฑ์)
- อย่าลืมเรียก
future.result()ในลูป — ถ้างานล้ม exception จะพุ่งตอนนั้น
import unittest
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
def work(n):
time.sleep(0.01 * (3 - n))
return n * 10
class AsCompletedTests(unittest.TestCase):
def test_yields_in_completion_order(self):
with ThreadPoolExecutor(max_workers=3) as pool:
futures = [pool.submit(work, i) for i in (0, 1, 2)]
done = [f.result() for f in as_completed(futures)]
self.assertEqual(sorted(done), [0, 10, 20])
self.assertEqual(done[0], 20) # n=2 sleeps least
if __name__ == "__main__":
unittest.main()
Recap
- เปลี่ยนจาก
executor.mapเป็นas_completedเมื่องานเสร็จไม่พร้อมกันและอยากตอบสนองเร็ว - เรียก
result()ในลูปและจับ exception ต่อ future - ตั้ง
timeoutในas_completed(...)ถ้าไม่อยากค้างทั้งชุด