Κατακτήστε τα asyncio Futures της Python. Εξερευνήστε ασύγχρονες έννοιες χαμηλού επιπέδου, πρακτικά παραδείγματα και προηγμένες τεχνικές για τη δημιουργία ισχυρών εφαρμογών υψηλής απόδοσης.
Asyncio Futures Ξεκλειδωμένα: Μια Εις Βάθος Εξερεύνηση στον Ασύγχρονο Προγραμματισμό Χαμηλού Επιπέδου στην Python
Στον κόσμο της σύγχρονης ανάπτυξης Python, η σύνταξη async/await
έχει γίνει ακρογωνιαίος λίθος για τη δημιουργία εφαρμογών υψηλής απόδοσης, που δεσμεύονται από I/O. Παρέχει έναν καθαρό, κομψό τρόπο για να γράψετε ταυτόχρονο κώδικα που μοιάζει σχεδόν σειριακός. Αλλά κάτω από αυτήν τη σύνταξη υψηλού επιπέδου βρίσκεται ένας ισχυρός και θεμελιώδης μηχανισμός: το Asyncio Future. Αν και μπορεί να μην αλληλεπιδράτε με raw Futures καθημερινά, η κατανόησή τους είναι το κλειδί για να κατακτήσετε πραγματικά τον ασύγχρονο προγραμματισμό στην Python. Είναι σαν να μαθαίνετε πώς λειτουργεί ο κινητήρας ενός αυτοκινήτου. Δεν χρειάζεται να το γνωρίζετε για να οδηγήσετε, αλλά είναι απαραίτητο αν θέλετε να είστε ένας μάστορας μηχανικός.
Αυτός ο περιεκτικός οδηγός θα αποκαλύψει τα μυστικά του asyncio
. Θα εξερευνήσουμε τι είναι τα Futures, πώς διαφέρουν από τις coroutines και τα tasks, και γιατί αυτό το πρωτόγονο χαμηλού επιπέδου είναι το θεμέλιο πάνω στο οποίο βασίζονται οι ασύγχρονες δυνατότητες της Python. Είτε κάνετε debugging σε μια σύνθετη κατάσταση αγώνα, είτε ενσωματώνεστε με παλαιότερες βιβλιοθήκες που βασίζονται σε callback, είτε απλά στοχεύετε σε μια βαθύτερη κατανόηση του async, αυτό το άρθρο είναι για εσάς.
Τι Ακριβώς Είναι ένα Asyncio Future;
Στον πυρήνα του, ένα asyncio.Future
είναι ένα αντικείμενο που αντιπροσωπεύει ένα ενδεχόμενο αποτέλεσμα μιας ασύγχρονης λειτουργίας. Σκεφτείτε το ως ένα placeholder, μια υπόσχεση ή μια απόδειξη για μια τιμή που δεν είναι ακόμη διαθέσιμη. Όταν ξεκινάτε μια λειτουργία που θα χρειαστεί χρόνο για να ολοκληρωθεί (όπως μια αίτηση δικτύου ή ένα ερώτημα βάσης δεδομένων), μπορείτε να λάβετε αμέσως ένα αντικείμενο Future. Το πρόγραμμά σας μπορεί να συνεχίσει να κάνει άλλες εργασίες και, όταν η λειτουργία τελικά ολοκληρωθεί, το αποτέλεσμα (ή ένα σφάλμα) θα τοποθετηθεί μέσα σε αυτό το αντικείμενο Future.
Μια χρήσιμη αναλογία από τον πραγματικό κόσμο είναι η παραγγελία ενός καφέ σε μια πολυσύχναστη καφετέρια. Κάνετε την παραγγελία σας και πληρώνετε, και ο barista σας δίνει μια απόδειξη με έναν αριθμό παραγγελίας. Δεν έχετε ακόμα τον καφέ σας, αλλά έχετε την απόδειξη — την υπόσχεση ενός καφέ. Μπορείτε τώρα να βρείτε ένα τραπέζι ή να ελέγξετε το τηλέφωνό σας αντί να στέκεστε αδρανείς στον πάγκο. Όταν ο καφές σας είναι έτοιμος, καλείται ο αριθμός σας και μπορείτε να «εξαργυρώσετε» την απόδειξή σας για το τελικό αποτέλεσμα. Η απόδειξη είναι το Future.
Τα βασικά χαρακτηριστικά ενός Future περιλαμβάνουν:
- Χαμηλού Επιπέδου: Τα Futures είναι ένα πιο πρωτόγονο δομικό στοιχείο σε σύγκριση με τα tasks. Δεν γνωρίζουν εγγενώς πώς να εκτελέσουν οποιονδήποτε κώδικα. Είναι απλώς containers για ένα αποτέλεσμα που θα οριστεί αργότερα.
- Awaitable: Το πιο σημαντικό χαρακτηριστικό ενός Future είναι ότι είναι ένα awaitable αντικείμενο. Αυτό σημαίνει ότι μπορείτε να χρησιμοποιήσετε τη λέξη-κλειδί
await
σε αυτό, η οποία θα διακόψει την εκτέλεση της coroutine σας μέχρι το Future να έχει ένα αποτέλεσμα. - Stateful: Ένα Future υπάρχει σε μία από τις λίγες διακριτές καταστάσεις καθ 'όλη τη διάρκεια του κύκλου ζωής του: Pending, Cancelled ή Finished.
Futures έναντι Coroutines έναντι Tasks: Διευκρινίζοντας τη Σύγχυση
Ένα από τα μεγαλύτερα εμπόδια για τους προγραμματιστές που είναι νέοι στο asyncio
είναι η κατανόηση της σχέσης μεταξύ αυτών των τριών βασικών εννοιών. Είναι βαθιά διασυνδεδεμένα, αλλά εξυπηρετούν διαφορετικούς σκοπούς.
1. Coroutines
Μια coroutine είναι απλώς μια συνάρτηση που ορίζεται με async def
. Όταν καλείτε μια συνάρτηση coroutine, δεν εκτελεί τον κώδικά της. Αντ 'αυτού, επιστρέφει ένα αντικείμενο coroutine. Αυτό το αντικείμενο είναι ένα σχέδιο για τον υπολογισμό, αλλά τίποτα δεν συμβαίνει μέχρι να οδηγηθεί από έναν βρόχο γεγονότων.
Παράδειγμα:
async def fetch_data(url): ...
Η κλήση fetch_data("http://example.com")
σας δίνει ένα αντικείμενο coroutine. Είναι αδρανές μέχρι να το await
ή να το προγραμματίσετε ως Task.
2. Tasks
Ένα asyncio.Task
είναι αυτό που χρησιμοποιείτε για να προγραμματίσετε μια coroutine να εκτελεστεί στον βρόχο γεγονότων ταυτόχρονα. Δημιουργείτε ένα Task χρησιμοποιώντας asyncio.create_task(my_coroutine())
. Ένα Task περικλείει την coroutine σας και την προγραμματίζει αμέσως να εκτελεστεί "στο παρασκήνιο" μόλις ο βρόχος γεγονότων έχει την ευκαιρία. Το σημαντικό πράγμα που πρέπει να κατανοήσετε εδώ είναι ότι ένα Task είναι μια υποκλάση του Future. Είναι ένα εξειδικευμένο Future που γνωρίζει πώς να οδηγήσει μια coroutine.
Όταν η περικλειόμενη coroutine ολοκληρωθεί και επιστρέψει μια τιμή, το Task (το οποίο, θυμηθείτε, είναι ένα Future) έχει αυτόματα το αποτέλεσμά του ορισμένο. Εάν η coroutine προκαλέσει μια εξαίρεση, η εξαίρεση του Task ορίζεται.
3. Futures
Ένα απλό asyncio.Future
είναι ακόμη πιο θεμελιώδες. Σε αντίθεση με ένα Task, δεν συνδέεται με καμία συγκεκριμένη coroutine. Είναι απλώς ένα κενό placeholder. Κάτι άλλο — ένα άλλο μέρος του κώδικά σας, μια βιβλιοθήκη ή ο ίδιος ο βρόχος γεγονότων — είναι υπεύθυνο για τον ρητό καθορισμό του αποτελέσματος ή της εξαίρεσής του αργότερα. Τα Tasks διαχειρίζονται αυτήν τη διαδικασία αυτόματα, αλλά με ένα raw Future, η διαχείριση είναι χειροκίνητη.
Ακολουθεί ένας συνοπτικός πίνακας για να γίνει σαφής η διάκριση:
Έννοια | Τι είναι | Πώς δημιουργείται | Βασική Περίπτωση Χρήσης |
---|---|---|---|
Coroutine | Μια συνάρτηση που ορίζεται με async def . Ένα σχέδιο υπολογισμού βασισμένο σε γεννήτρια. |
async def my_func(): ... |
Ορισμός ασύγχρονης λογικής. |
Task | Μια Υποκλάση Future που περικλείει και εκτελεί μια coroutine στον βρόχο γεγονότων. | 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: Finishing (Ορισμός Αποτελέσματος ή Εξαίρεσης)
Ένα pending 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
Ένα pending Future μπορεί επίσης να ακυρωθεί καλώντας τη μέθοδο future.cancel()
. Αυτό είναι ένα αίτημα για εγκατάλειψη της λειτουργίας. Εάν η ακύρωση είναι επιτυχής, το Future εισέρχεται σε μια κατάσταση cancelled. Όταν αναμένεται, ένα ακυρωμένο Future θα προκαλέσει ένα CancelledError
.
Εργασία με Futures: Πρακτικά Παραδείγματα
Η θεωρία είναι σημαντική, αλλά ο κώδικας το κάνει πραγματικό. Ας δούμε πώς μπορείτε να χρησιμοποιήσετε raw Futures για να λύσετε συγκεκριμένα προβλήματα.
Παράδειγμα 1: Ένα Χειροκίνητο Σενάριο Παραγωγού/Καταναλωτή
Αυτό είναι το κλασικό παράδειγμα που δείχνει το βασικό μοτίβο επικοινωνίας. Θα έχουμε μια 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. Αυτό αποσυνδέει τον παραγωγό και τον καταναλωτή, το οποίο είναι ένα πολύ ισχυρό μοτίβο σε ταυτόχρονα συστήματα.
Παράδειγμα 2: Γεφύρωση APIs που Βασίζονται σε Callback
Αυτή είναι μία από τις πιο ισχυρές και κοινές περιπτώσεις χρήσης για raw Futures. Πολλές παλαιότερες βιβλιοθήκες (ή βιβλιοθήκες που πρέπει να διασυνδεθούν με C/C++) δεν είναι εγγενείς `async/await`. Αντ 'αυτού, χρησιμοποιούν ένα στυλ που βασίζεται σε callback, όπου περνάτε μια συνάρτηση που θα εκτελεστεί κατά την ολοκλήρωση.
Τα Futures παρέχουν μια τέλεια γέφυρα για τον εκσυγχρονισμό αυτών των APIs. Μπορούμε να δημιουργήσουμε μια συνάρτηση wrapper που επιστρέφει ένα awaitable Future.
Ας φανταστούμε ότι έχουμε μια υποθετική συνάρτηση παλαιού τύπου 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` που μπορεί να αναμένεται. Έχουμε "futurized" με επιτυχία ένα legacy API.
Σημείωση: Η χρήση του loop.call_soon_threadsafe
είναι κρίσιμη όταν το callback εκτελείται από ένα διαφορετικό thread, όπως συμβαίνει συχνά με τις λειτουργίες I/O σε βιβλιοθήκες που δεν είναι ενσωματωμένες με το asyncio. Διασφαλίζει ότι το future.set_result
καλείται με ασφάλεια στο πλαίσιο του βρόχου γεγονότων asyncio.
Πότε να Χρησιμοποιήσετε Raw Futures (Και Πότε Όχι)
Με τις ισχυρές αφαιρέσεις υψηλού επιπέδου που είναι διαθέσιμες, είναι σημαντικό να γνωρίζετε πότε να χρησιμοποιήσετε ένα εργαλείο χαμηλού επιπέδου όπως ένα Future.
Χρησιμοποιήστε Raw Futures Όταν:
- Διασύνδεση με κώδικα που βασίζεται σε callback: Όπως φαίνεται στο παραπάνω παράδειγμα, αυτή είναι η κύρια περίπτωση χρήσης. Τα Futures είναι η ιδανική γέφυρα.
- Δημιουργία προσαρμοσμένων primitives συγχρονισμού: Εάν χρειάζεται να δημιουργήσετε τη δική σας έκδοση ενός Event, Lock ή Queue με συγκεκριμένες συμπεριφορές, τα Futures θα είναι το βασικό στοιχείο πάνω στο οποίο θα βασιστείτε.
- Ένα αποτέλεσμα παράγεται από κάτι άλλο εκτός από μια coroutine: Εάν ένα αποτέλεσμα δημιουργείται από μια εξωτερική πηγή γεγονότων (π.χ. ένα σήμα από μια άλλη διεργασία, ένα μήνυμα από έναν πελάτη websocket), ένα Future είναι ο τέλειος τρόπος για να αντιπροσωπεύσετε αυτό το εκκρεμές συμβάν στον κόσμο του asyncio.
Αποφύγετε Raw Futures (Χρησιμοποιήστε Tasks Αντ 'Αυτού) Όταν:
- Απλώς θέλετε να εκτελέσετε μια coroutine ταυτόχρονα: Αυτή είναι η δουλειά του
asyncio.create_task()
. Διαχειρίζεται το περιτύλιγμα της coroutine, τον προγραμματισμό της και τη διάδοση του αποτελέσματος ή της εξαίρεσής της στο Task (το οποίο είναι ένα Future). Η χρήση ενός raw Future εδώ θα ήταν επανεφεύρεση του τροχού. - Διαχείριση ομάδων ταυτόχρονων λειτουργιών: Για την εκτέλεση πολλών coroutines και την αναμονή για την ολοκλήρωσή τους, τα APIs υψηλού επιπέδου όπως
asyncio.gather()
,asyncio.wait()
καιasyncio.as_completed()
είναι πολύ ασφαλέστερα, πιο ευανάγνωστα και λιγότερο επιρρεπή σε σφάλματα. Αυτές οι συναρτήσεις λειτουργούν απευθείας σε coroutines και Tasks.
Προηγμένες Έννοιες και Παγίδες
Futures και ο Βρόχος Γεγονότων
Ένα Future συνδέεται εγγενώς με τον βρόχο γεγονότων στον οποίο δημιουργήθηκε. Μια έκφραση `await future` λειτουργεί επειδή ο βρόχος γεγονότων γνωρίζει αυτό το συγκεκριμένο Future. Κατανοεί ότι όταν βλέπει ένα `await` σε ένα pending Future, θα πρέπει να αναστείλει την τρέχουσα coroutine και να αναζητήσει άλλες εργασίες για να κάνει. Όταν το Future ολοκληρωθεί τελικά, ο βρόχος γεγονότων γνωρίζει ποια ανασταλμένη coroutine να ξυπνήσει.
Αυτός είναι ο λόγος για τον οποίο πρέπει πάντα να δημιουργείτε ένα Future χρησιμοποιώντας loop.create_future()
, όπου το loop
είναι ο τρέχων βρόχος γεγονότων. Η προσπάθεια δημιουργίας και χρήσης Futures σε διαφορετικούς βρόχους γεγονότων (ή διαφορετικά threads χωρίς τον κατάλληλο συγχρονισμό) θα οδηγήσει σε σφάλματα και απρόβλεπτη συμπεριφορά.
Τι Κάνει Πραγματικά το `await`
Όταν ο διερμηνέας της Python συναντήσει result = await my_future
, εκτελεί μερικά βήματα κάτω από την επιφάνεια:
- Καλεί το
my_future.__await__()
, το οποίο επιστρέφει έναν iterator. - Ελέγχει εάν το future έχει ήδη ολοκληρωθεί. Εάν ναι, λαμβάνει το αποτέλεσμα (ή προκαλεί την εξαίρεση) και συνεχίζει χωρίς αναστολή.
- Εάν το future είναι pending, λέει στον βρόχο γεγονότων: "Αναστείλετε την εκτέλεσή μου και παρακαλώ ξυπνήστε με όταν αυτό το συγκεκριμένο future ολοκληρωθεί."
- Ο βρόχος γεγονότων αναλαμβάνει στη συνέχεια, εκτελώντας άλλα έτοιμα tasks.
- Μόλις κληθεί το
my_future.set_result()
ή τοmy_future.set_exception()
, ο βρόχος γεγονότων επισημαίνει το Future ως done και προγραμματίζει την ανασταλμένη coroutine να συνεχιστεί στην επόμενη επανάληψη του βρόχου.
Συνήθης Παγίδα: Σύγχυση 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. Είναι το πρωτόγονο χαμηλού επιπέδου που κάνει την μαγεία υψηλού επιπέδου του async/await
δυνατή. Ενώ η καθημερινή σας κωδικοποίηση θα περιλαμβάνει κυρίως τη σύνταξη coroutines και τον προγραμματισμό τους ως Tasks, η κατανόηση των Futures σας παρέχει μια βαθιά εικόνα για το πώς συνδέονται τα πάντα.
Με την κατάκτηση των Futures, αποκτάτε την ικανότητα να:
- Κάνετε debugging με αυτοπεποίθηση: Όταν βλέπετε ένα
CancelledError
ή μια coroutine που δεν επιστρέφει ποτέ, θα κατανοήσετε την κατάσταση του υποκείμενου Future ή Task. - Ενσωματώνετε οποιονδήποτε κώδικα: Έχετε τώρα τη δύναμη να περικλείσετε οποιοδήποτε API που βασίζεται σε callback και να το κάνετε πολίτη πρώτης κατηγορίας στον σύγχρονο ασύγχρονο κόσμο.
- Δημιουργείτε εξελιγμένα εργαλεία: Η γνώση των Futures είναι το πρώτο βήμα προς τη δημιουργία των δικών σας προηγμένων ταυτόχρονων και παράλληλων κατασκευών προγραμματισμού.
Έτσι, την επόμενη φορά που θα χρησιμοποιήσετε το asyncio.create_task()
ή το await asyncio.gather()
, αφιερώστε μια στιγμή για να εκτιμήσετε το ταπεινό Future που εργάζεται ακούραστα στο παρασκήνιο. Είναι το στέρεο θεμέλιο πάνω στο οποίο χτίζονται ισχυρές, επεκτάσιμες και κομψές ασύγχρονες εφαρμογές Python.