เชี่ยวชาญ asyncio Futures ของ Python สำรวจแนวคิดอะซิงโครนัสระดับต่ำ ตัวอย่างเชิงปฏิบัติ และเทคนิคขั้นสูงเพื่อสร้างแอปพลิเคชันที่แข็งแกร่งและมีประสิทธิภาพสูง
ปลดล็อก Asyncio Futures: เจาะลึกการเขียนโปรแกรมแบบอะซิงโครนัสระดับต่ำใน Python
ในโลกของการพัฒนา Python สมัยใหม่ ไวยากรณ์ async/await
ได้กลายเป็นรากฐานสำคัญสำหรับการสร้างแอปพลิเคชันที่มีประสิทธิภาพสูงและเน้น I/O เป็นหลัก มันมอบวิธีที่สะอาดและสง่างามในการเขียนโค้ดที่ทำงานพร้อมกันซึ่งดูเกือบจะเรียงตามลำดับ แต่ภายใต้ความสะดวกสบายของไวยากรณ์ระดับสูงนี้ มีกลไกที่ทรงพลังและพื้นฐานซ่อนอยู่ นั่นคือ Asyncio Future แม้ว่าคุณอาจจะไม่ได้โต้ตอบกับ Futures แบบดิบทุกวัน แต่การทำความเข้าใจมันเป็นกุญแจสำคัญสู่การเชี่ยวชาญการเขียนโปรแกรมแบบอะซิงโครนัสใน Python อย่างแท้จริง มันเหมือนกับการเรียนรู้ว่าเครื่องยนต์ของรถยนต์ทำงานอย่างไร คุณไม่จำเป็นต้องรู้เพื่อขับรถ แต่จำเป็นอย่างยิ่งหากคุณต้องการเป็นช่างเครื่องผู้เชี่ยวชาญ
คู่มือฉบับสมบูรณ์นี้จะเปิดเผยเบื้องหลังของ asyncio
เราจะสำรวจว่า Futures คืออะไร แตกต่างจาก coroutines และ tasks อย่างไร และทำไมเครื่องมือพื้นฐานระดับต่ำนี้จึงเป็นรากฐานที่สร้างขีดความสามารถแบบอะซิงโครนัสของ Python ขึ้นมา ไม่ว่าคุณจะกำลังดีบัก race condition ที่ซับซ้อน การผนวกรวมกับไลบรารีที่ใช้ callback แบบเก่า หรือเพียงแค่ต้องการทำความเข้าใจ async ให้ลึกซึ้งยิ่งขึ้น บทความนี้เหมาะสำหรับคุณ
Asyncio Future คืออะไรกันแน่?
โดยแก่นแท้แล้ว asyncio.Future
คือออบเจกต์ที่แสดงถึง ผลลัพธ์ที่จะเกิดขึ้นในอนาคต ของการดำเนินการแบบอะซิงโครนัส ลองนึกภาพว่าเป็นตัวยึด, คำสัญญา, หรือใบเสร็จสำหรับค่าที่ยังไม่พร้อมใช้งาน เมื่อคุณเริ่มต้นการดำเนินการที่ต้องใช้เวลาในการทำให้เสร็จสมบูรณ์ (เช่น การร้องขอเครือข่ายหรือการสอบถามฐานข้อมูล) คุณจะได้รับออบเจกต์ Future กลับมาทันที โปรแกรมของคุณสามารถทำงานอื่นต่อไปได้ และเมื่อการดำเนินการเสร็จสิ้นในที่สุด ผลลัพธ์ (หรือข้อผิดพลาด) จะถูกวางไว้ภายในออบเจกต์ Future นั้น
การเปรียบเทียบในโลกแห่งความเป็นจริงที่ช่วยให้เข้าใจคือการสั่งกาแฟที่ร้านกาแฟที่พลุกพล่าน คุณสั่งและจ่ายเงิน และบาริสต้าจะให้ใบเสร็จพร้อมหมายเลขคำสั่งซื้อ คุณยังไม่มีกาแฟของคุณ แต่คุณมีใบเสร็จ—ซึ่งเป็น คำสัญญา ของกาแฟ คุณสามารถไปหาโต๊ะหรือเช็คโทรศัพท์แทนที่จะยืนรอเฉยๆ ที่เคาน์เตอร์ เมื่อกาแฟของคุณพร้อม หมายเลขของคุณจะถูกเรียก และคุณสามารถ 'แลก' ใบเสร็จของคุณเป็นผลลัพธ์สุดท้ายได้ ใบเสร็จนั้นคือ Future
ลักษณะสำคัญของ Future ได้แก่:
- ระดับต่ำ: Futures เป็นบล็อกการสร้างที่ดั้งเดิมกว่าเมื่อเทียบกับ tasks พวกมันไม่รู้โดยธรรมชาติว่าจะเรียกใช้โค้ดใดๆ พวกมันเป็นเพียงคอนเทนเนอร์สำหรับผลลัพธ์ที่จะถูกกำหนดในภายหลัง
- รอได้ (Awaitable): คุณสมบัติที่สำคัญที่สุดของ Future คือมันเป็นออบเจกต์ที่ รอได้ ซึ่งหมายความว่าคุณสามารถใช้คีย์เวิร์ด
await
กับมันได้ ซึ่งจะหยุดการทำงานของ coroutine ของคุณชั่วคราวจนกว่า Future จะมีผลลัพธ์ - มีสถานะ (Stateful): Future มีอยู่ในสถานะที่แตกต่างกันไม่กี่สถานะตลอดวงจรชีวิตของมัน: รอการดำเนินการ (Pending), ถูกยกเลิก (Cancelled), หรือ เสร็จสิ้น (Finished).
Futures vs. Coroutines vs. Tasks: ไขความสับสน
หนึ่งในอุปสรรคที่ใหญ่ที่สุดสำหรับนักพัฒนาที่เพิ่งเริ่มใช้ asyncio
คือการทำความเข้าใจความสัมพันธ์ระหว่างแนวคิดหลักสามประการนี้ พวกมันเชื่อมโยงกันอย่างลึกซึ้งแต่มีวัตถุประสงค์ที่แตกต่างกัน
1. Coroutines
Coroutine เป็นเพียงฟังก์ชันที่นิยามด้วย async def
เมื่อคุณเรียกฟังก์ชัน coroutine มันจะไม่รันโค้ดทันที แต่จะคืนค่า ออบเจกต์ coroutine ออบเจกต์นี้เป็นพิมพ์เขียวสำหรับการคำนวณ แต่จะไม่มีอะไรเกิดขึ้นจนกว่าจะถูกขับเคลื่อนโดย event loop
ตัวอย่าง:
async def fetch_data(url): ...
การเรียก fetch_data("http://example.com")
จะให้คุณได้ออบเจกต์ coroutine ซึ่งจะไม่มีการทำงานจนกว่าคุณจะ await
หรือจัดตารางเป็น Task
2. Tasks
asyncio.Task
คือสิ่งที่คุณใช้ในการจัดตาราง coroutine ให้ทำงานบน event loop พร้อมกัน คุณสร้าง Task โดยใช้ asyncio.create_task(my_coroutine())
Task จะห่อหุ้ม coroutine ของคุณและจัดตารางให้ทำงาน "เบื้องหลัง" ทันทีที่ event loop มีโอกาส สิ่งสำคัญที่ต้องเข้าใจคือ Task เป็นคลาสย่อยของ Future มันคือ Future ที่มีความเชี่ยวชาญซึ่งรู้ว่าจะขับเคลื่อน coroutine ได้อย่างไร
เมื่อ coroutine ที่ถูกห่อหุ้มทำงานเสร็จสิ้นและคืนค่า Task (ซึ่งจำไว้ว่าเป็น Future) จะมีการตั้งค่าผลลัพธ์โดยอัตโนมัติ หาก coroutine เกิดข้อผิดพลาด Task ก็จะมีการตั้งค่าข้อผิดพลาดนั้น
3. Futures
asyncio.Future
แบบธรรมดานั้นเป็นพื้นฐานยิ่งกว่านั้น แตกต่างจาก Task มันไม่ได้ผูกติดกับ coroutine เฉพาะใดๆ มันเป็นเพียงตัวยึดที่ว่างเปล่า สิ่งอื่น—ส่วนอื่นของโค้ดของคุณ, ไลบรารี, หรือ event loop เอง—มีหน้าที่รับผิดชอบในการตั้งค่าผลลัพธ์หรือข้อผิดพลาดอย่างชัดเจนในภายหลัง Tasks จะจัดการกระบวนการนี้ให้คุณโดยอัตโนมัติ แต่ด้วย Future แบบดิบ การจัดการจะต้องทำด้วยตนเอง
นี่คือตารางสรุปเพื่อให้ความแตกต่างชัดเจน:
แนวคิด | คืออะไร | สร้างอย่างไร | กรณีการใช้งานหลัก |
---|---|---|---|
Coroutine | ฟังก์ชันที่นิยามด้วย async def ; พิมพ์เขียวการคำนวณที่ใช้ generator. |
async def my_func(): ... |
การกำหนดตรรกะแบบอะซิงโครนัส |
Task | คลาสย่อยของ Future ที่ห่อหุ้มและรัน coroutine บน event loop. | asyncio.create_task(my_func()) |
การรัน coroutines พร้อมกัน ("เรียกใช้แล้วลืม"). |
Future | ออบเจกต์ awaitable ระดับต่ำที่แสดงถึงผลลัพธ์ที่จะเกิดขึ้นในอนาคต | loop.create_future() |
การเชื่อมต่อกับโค้ดแบบ callback; การซิงโครไนซ์แบบกำหนดเอง |
กล่าวโดยสรุป: คุณเขียน Coroutines คุณรันมันพร้อมกันโดยใช้ Tasks ทั้ง Tasks และการดำเนินการ I/O พื้นฐานใช้ Futures เป็นกลไกพื้นฐานสำหรับการส่งสัญญาณการทำงานเสร็จสิ้น
วงจรชีวิตของ Future
Future จะเปลี่ยนผ่านสถานะต่างๆ ที่เรียบง่ายแต่สำคัญ การทำความเข้าใจวงจรชีวิตนี้เป็นกุญแจสำคัญในการใช้งานอย่างมีประสิทธิภาพ
สถานะที่ 1: รอการดำเนินการ (Pending)
เมื่อ Future ถูกสร้างขึ้นครั้งแรก มันจะอยู่ในสถานะ รอการดำเนินการ (pending) ไม่มีผลลัพธ์และไม่มีข้อผิดพลาด มันกำลังรอให้มีคนดำเนินการให้เสร็จสิ้น
import asyncio
async def main():
# Get the current event loop
loop = asyncio.get_running_loop()
# Create a new Future
my_future = loop.create_future()
print(f"Is the future done? {my_future.done()}") # Output: False
# To run the main coroutine
asyncio.run(main())
สถานะที่ 2: กำลังเสร็จสิ้น (การตั้งค่าผลลัพธ์หรือข้อผิดพลาด)
Future ที่อยู่ในสถานะรอการดำเนินการสามารถเสร็จสิ้นได้สองวิธี ซึ่งมักจะดำเนินการโดย "ผู้ผลิต" ผลลัพธ์
1. การตั้งค่าผลลัพธ์ที่สำเร็จด้วย set_result()
:
เมื่อการดำเนินการแบบอะซิงโครนัสเสร็จสมบูรณ์ ผลลัพธ์จะถูกแนบไปกับ Future โดยใช้วิธีนี้ สิ่งนี้จะเปลี่ยน Future ไปสู่สถานะ เสร็จสิ้น (finished).
2. การตั้งค่าข้อผิดพลาดด้วย set_exception()
:
หากการดำเนินการล้มเหลว ออบเจกต์ข้อผิดพลาดจะถูกแนบไปกับ Future สิ่งนี้จะเปลี่ยน Future ไปสู่สถานะ เสร็จสิ้น (finished) เช่นกัน เมื่อ coroutine `await` Future นี้ ข้อผิดพลาดที่แนบมาจะถูกยกขึ้น
สถานะที่ 3: เสร็จสิ้น (Finished)
เมื่อผลลัพธ์หรือข้อผิดพลาดถูกตั้งค่าแล้ว Future จะถือว่า เสร็จสมบูรณ์ (done) สถานะของมันจะสิ้นสุดและไม่สามารถเปลี่ยนแปลงได้ คุณสามารถตรวจสอบได้ด้วยเมธอด future.done()
Coroutines ใดๆ ที่กำลัง await
Future นี้จะตื่นขึ้นมาและดำเนินการต่อ
(ทางเลือก) สถานะที่ 4: ถูกยกเลิก (Cancelled)
Future ที่รอการดำเนินการสามารถถูกยกเลิกได้โดยการเรียกเมธอด future.cancel()
นี่คือคำขอให้ยกเลิกการดำเนินการ หากการยกเลิกสำเร็จ Future จะเข้าสู่สถานะ ถูกยกเลิก (cancelled) เมื่อถูก await, Future ที่ถูกยกเลิกจะยก CancelledError
ขึ้นมา
การทำงานกับ Futures: ตัวอย่างเชิงปฏิบัติ
ทฤษฎีเป็นสิ่งสำคัญ แต่โค้ดทำให้มันเป็นจริง มาดูกันว่าคุณสามารถใช้ Futures แบบดิบเพื่อแก้ปัญหาเฉพาะได้อย่างไร
ตัวอย่างที่ 1: สถานการณ์ Producer/Consumer แบบแมนนวล
นี่คือตัวอย่างคลาสสิกที่แสดงรูปแบบการสื่อสารหลัก เราจะมี coroutine หนึ่งตัว (`consumer`) ที่รอ Future และอีกตัวหนึ่ง (`producer`) ที่ทำงานบางอย่างแล้วตั้งค่าผลลัพธ์บน Future นั้น
import asyncio
import time
async def producer(future):
print("Producer: Starting to work on a heavy calculation...")
await asyncio.sleep(2) # Simulate I/O or CPU-intensive work
result = 42
print(f"Producer: Calculation finished. Setting result: {result}")
future.set_result(result)
async def consumer(future):
print("Consumer: Waiting for the result...")
# The 'await' keyword pauses the consumer here until the future is done
result = await future
print(f"Consumer: Got the result! It's {result}")
async def main():
loop = asyncio.get_running_loop()
my_future = loop.create_future()
# Schedule the producer to run in the background
# It will work on completing my_future
asyncio.create_task(producer(my_future))
# The consumer will wait for the producer to finish via the future
await consumer(my_future)
asyncio.run(main())
# Expected Output:
# Consumer: Waiting for the result...
# Producer: Starting to work on a heavy calculation...
# (2-second pause)
# Producer: Calculation finished. Setting result: 42
# Consumer: Got the result! It's 42
ในตัวอย่างนี้ Future ทำหน้าที่เป็นจุดซิงโครไนซ์ `consumer` ไม่รู้หรือไม่สนใจว่าใครเป็นผู้ให้ผลลัพธ์ มันเพียงแค่สนใจ Future เอง สิ่งนี้แยกส่วน producer และ consumer ออกจากกัน ซึ่งเป็นรูปแบบที่ทรงพลังมากในระบบที่ทำงานพร้อมกัน
ตัวอย่างที่ 2: การเชื่อมต่อ API ที่ใช้ Callback
นี่เป็นหนึ่งในกรณีการใช้งานที่ทรงพลังและพบบ่อยที่สุดสำหรับ Futures แบบดิบ ไลบรารีเก่าจำนวนมาก (หรือไลบรารีที่ต้องการเชื่อมต่อกับ C/C++) ไม่ได้รองรับ `async/await` โดยตรง แต่จะใช้รูปแบบที่อ้างอิง callback โดยที่คุณส่งฟังก์ชันที่จะถูกเรียกใช้เมื่อการทำงานเสร็จสิ้น
Futures เป็นสะพานเชื่อมที่สมบูรณ์แบบในการทำให้ API เหล่านี้ทันสมัยขึ้น เราสามารถสร้างฟังก์ชัน wrapper ที่คืนค่า Future ที่สามารถ await ได้
สมมติว่าเรามีฟังก์ชันเก่าแก่สมมุติ legacy_fetch(url, callback)
ที่ดึง URL และเรียก `callback(data)` เมื่อเสร็จสิ้น
import asyncio
from threading import Timer
# --- This is our hypothetical legacy library ---
def legacy_fetch(url, callback):
# This function is not async and uses callbacks.
# We simulate a network delay using a timer from the threading module.
print(f"[Legacy] Fetching {url}... (This is a blocking-style call)")
def on_done():
data = f"Some data from {url}"
callback(data)
# Simulate a 2-second network call
Timer(2, on_done).start()
# -----------------------------------------------
async def modern_fetch(url):
"""Our awaitable wrapper around the legacy function."""
loop = asyncio.get_running_loop()
future = loop.create_future()
def on_fetch_complete(data):
# This callback will be executed in a different thread.
# To safely set the result on the future belonging to the main event loop,
# we use loop.call_soon_threadsafe.
loop.call_soon_threadsafe(future.set_result, data)
# Call the legacy function with our special callback
legacy_fetch(url, on_fetch_complete)
# Await the future, which will be completed by our callback
return await future
async def main():
print("Starting modern fetch...")
data = await modern_fetch("http://example.com")
print(f"Modern fetch complete. Received: '{data}'")
asyncio.run(main())
รูปแบบนี้มีประโยชน์อย่างเหลือเชื่อ ฟังก์ชัน `modern_fetch` ซ่อนความซับซ้อนของ callback ทั้งหมด จากมุมมองของ `main` มันเป็นเพียงฟังก์ชัน `async` ทั่วไปที่สามารถ await ได้ เราได้ "futurized" API แบบเก่าเรียบร้อยแล้ว
หมายเหตุ: การใช้ loop.call_soon_threadsafe
เป็นสิ่งสำคัญอย่างยิ่งเมื่อ callback ถูกเรียกใช้โดยเธรดอื่น ซึ่งเป็นเรื่องปกติสำหรับการดำเนินการ I/O ในไลบรารีที่ไม่ได้รวมเข้ากับ asyncio มันช่วยให้มั่นใจว่า future.set_result
ถูกเรียกใช้อย่างปลอดภัยภายในบริบทของ asyncio event loop
เมื่อไหร่ควรใช้ Raw Futures (และเมื่อไหร่ไม่ควรใช้)
ด้วยนามธรรมระดับสูงที่ทรงพลังที่มีอยู่ เป็นสิ่งสำคัญที่จะต้องรู้ว่าเมื่อใดควรใช้เครื่องมือระดับต่ำอย่าง Future
ใช้ Raw Futures เมื่อ:
- การเชื่อมต่อกับโค้ดที่ใช้ callback: ดังที่แสดงในตัวอย่างข้างต้น นี่คือกรณีการใช้งานหลัก Futures เป็นสะพานเชื่อมในอุดมคติ
- การสร้าง primitive การซิงโครไนซ์แบบกำหนดเอง: หากคุณต้องการสร้าง Event, Lock, หรือ Queue ในเวอร์ชันของคุณเองด้วยพฤติกรรมเฉพาะ Futures จะเป็นส่วนประกอบหลักที่คุณจะสร้างขึ้นมา
- ผลลัพธ์ถูกสร้างโดยสิ่งอื่นที่ไม่ใช่ coroutine: หากผลลัพธ์ถูกสร้างโดยแหล่งกำเนิดเหตุการณ์ภายนอก (เช่น สัญญาณจากกระบวนการอื่น, ข้อความจากไคลเอนต์ websocket) Future เป็นวิธีที่สมบูรณ์แบบในการแสดงเหตุการณ์ที่รอดำเนินการนั้นในโลกของ asyncio
หลีกเลี่ยง Raw Futures (ใช้ Tasks แทน) เมื่อ:
- คุณเพียงแค่ต้องการรัน coroutine พร้อมกัน: นี่คือหน้าที่ของ
asyncio.create_task()
ซึ่งจะจัดการการห่อหุ้ม coroutine การจัดตาราง และการส่งต่อผลลัพธ์หรือข้อผิดพลาดไปยัง Task (ซึ่งเป็น Future) การใช้ Raw Future ที่นี่จะเป็นการประดิษฐ์ล้อใหม่ - การจัดการกลุ่มของการดำเนินการพร้อมกัน: สำหรับการรัน coroutines หลายตัวและรอให้พวกมันเสร็จสิ้น API ระดับสูงเช่น
asyncio.gather()
,asyncio.wait()
, และasyncio.as_completed()
นั้นปลอดภัยกว่า อ่านง่ายกว่า และมีข้อผิดพลาดน้อยกว่ามาก ฟังก์ชันเหล่านี้ทำงานโดยตรงกับ coroutines และ Tasks
แนวคิดและข้อควรระวังขั้นสูง
Futures และ Event Loop
Future มีความเชื่อมโยงอย่างใกล้ชิดกับ event loop ที่มันถูกสร้างขึ้น นิพจน์ `await future` ทำงานได้เพราะ event loop รู้จัก Future เฉพาะนี้ มันเข้าใจว่าเมื่อเห็น `await` บน Future ที่รอการดำเนินการ มันควรจะระงับ coroutine ปัจจุบันและมองหางานอื่นที่จะทำ เมื่อ Future เสร็จสมบูรณ์ในที่สุด event loop จะรู้ว่า coroutine ที่ถูกระงับตัวใดที่จะปลุกขึ้นมา
นี่คือเหตุผลที่คุณต้องสร้าง Future โดยใช้ loop.create_future()
เสมอ โดยที่ loop
คือ event loop ที่กำลังทำงานอยู่ การพยายามสร้างและใช้ Futures ข้าม event loop ที่แตกต่างกัน (หรือเธรดที่แตกต่างกันโดยไม่มีการซิงโครไนซ์ที่เหมาะสม) จะนำไปสู่ข้อผิดพลาดและพฤติกรรมที่ไม่สามารถคาดเดาได้
`await` ทำอะไรจริงๆ
เมื่อตัวแปล Python พบ result = await my_future
มันจะดำเนินการตามขั้นตอนบางอย่างเบื้องหลัง:
- มันเรียก
my_future.__await__()
ซึ่งจะคืนค่า iterator - มันตรวจสอบว่า future เสร็จสิ้นแล้วหรือไม่ หากเสร็จสิ้น มันจะดึงผลลัพธ์ (หรือยกข้อผิดพลาด) และดำเนินการต่อโดยไม่ระงับ
- หาก future กำลังรอการดำเนินการ มันจะบอก event loop ว่า: "ระงับการทำงานของฉัน และโปรดปลุกฉันเมื่อ future เฉพาะนี้ เสร็จสมบูรณ์"
- จากนั้น event loop จะเข้าควบคุม โดยรันงานอื่นๆ ที่พร้อม
- เมื่อ
my_future.set_result()
หรือmy_future.set_exception()
ถูกเรียก event loop จะทำเครื่องหมาย Future ว่าเสร็จสิ้นและจัดตาราง coroutine ที่ถูกระงับให้กลับมาทำงานต่อในการวนซ้ำครั้งถัดไปของ loop
ข้อผิดพลาดทั่วไป: สับสนระหว่าง Futures กับ Tasks
ข้อผิดพลาดทั่วไปคือการพยายามจัดการการทำงานของ coroutine ด้วยตนเองโดยใช้ Future ในขณะที่ Task เป็นเครื่องมือที่เหมาะสม
วิธีที่ผิด (ซับซ้อนเกินไป):
# This is verbose and unnecessary
async def main_wrong():
loop = asyncio.get_running_loop()
future = loop.create_future()
# A separate coroutine to run our target and set the future
async def runner():
try:
result = await some_other_coro()
future.set_result(result)
except Exception as e:
future.set_exception(e)
# We have to manually schedule this runner coroutine
asyncio.create_task(runner())
# Finally, we can await our future
final_result = await future
วิธีที่ถูกต้อง (ใช้ Task):
# A Task does all of the above for you!
async def main_right():
# A Task is a Future that automatically drives a coroutine
task = asyncio.create_task(some_other_coro())
# We can await the task directly
final_result = await task
เนื่องจาก Task
เป็นคลาสย่อยของ Future
ตัวอย่างที่สองจึงไม่เพียงแค่สะอาดกว่า แต่ยังเทียบเท่ากันในด้านฟังก์ชันการทำงานและมีประสิทธิภาพมากกว่า
สรุป: รากฐานของ Asyncio
Asyncio Future คือฮีโร่ผู้ปิดทองหลังพระของระบบนิเวศอะซิงโครนัสของ Python มันคือ primitive ระดับต่ำที่ทำให้ความมหัศจรรย์ระดับสูงของ async/await
เป็นไปได้ ในขณะที่การเขียนโค้ดในแต่ละวันของคุณจะเกี่ยวข้องกับการเขียน coroutines และจัดตารางเป็น Tasks เป็นหลัก การทำความเข้าใจ Futures จะช่วยให้คุณได้รับข้อมูลเชิงลึกอย่างลึกซึ้งว่าทุกสิ่งเชื่อมโยงกันอย่างไร
ด้วยการเชี่ยวชาญ Futures คุณจะได้รับความสามารถในการ:
- ดีบักได้อย่างมั่นใจ: เมื่อคุณเห็น
CancelledError
หรือ coroutine ที่ไม่เคยคืนค่า คุณจะเข้าใจสถานะของ Future หรือ Task ที่อยู่เบื้องหลัง - ผสานรวมโค้ดใดๆ: ตอนนี้คุณมีพลังในการห่อหุ้ม API ที่ใช้ callback และทำให้มันเป็นพลเมืองชั้นหนึ่งในโลก async สมัยใหม่
- สร้างเครื่องมือที่ซับซ้อน: ความรู้เกี่ยวกับ Futures เป็นก้าวแรกสู่การสร้างโครงสร้างการเขียนโปรแกรมแบบ concurrent และ parallel ขั้นสูงของคุณเอง
ดังนั้น ครั้งต่อไปที่คุณใช้ asyncio.create_task()
หรือ await asyncio.gather()
โปรดใช้เวลาสักครู่เพื่อชื่นชม Future ผู้ถ่อมตนที่ทำงานอย่างไม่รู้จักเหน็ดเหนื่อยเบื้องหลัง มันคือรากฐานที่มั่นคงซึ่งแอปพลิเคชัน Python แบบอะซิงโครนัสที่แข็งแกร่ง ปรับขนาดได้ และสง่างามถูกสร้างขึ้น