Python async / await Επεξήγηση: The 2026 Tutorial
Το Async στην Python έχει τη φήμη ότι προκαλεί σύγχυση. Δεν χρειάζεται να είναι. Μόλις εσωτερικοποιήσετε μια πρόταση — async επιτρέπει σε ΕΝΑ νήμα να εκτελεί πολλαπλές εργασίες συνδεδεμένες με I/O — όλα τα άλλα ακολουθούν.
Αυτό το σεμινάριο καλύπτει: τι κάνουν στην πραγματικότητα το "async def" και το "wait", όταν το async κερδίζει έναντι όταν είναι το λάθος εργαλείο, τα τέσσερα μοτίβα που χρησιμοποιεί κάθε async codebase (sequential, collect, semaphore, timeout) και τους τρεις τρόπους με τους οποίους οι αρχάριοι καταπίνουν σιωπηλά τα σφάλματα.
Το νοητικό μοντέλο της μίας πρότασης
Το Async στην Python είναι συνεργατική συγχρονισμός σε ένα μόνο νήμα. Όταν ο κώδικάς σας χτυπήσει «αναμονή», ο έλεγχος επιστρέφει στον βρόχο συμβάντος, ο οποίος μπορεί να εκτελέσει μια άλλη εργασία ενώ η πρώτη περιμένει για I/O. Όταν ολοκληρωθεί το I/O, ο βρόχος συνεχίζει την πρώτη εργασία από το σημείο που σταμάτησε.
Αυτό είναι όλο. Χωρίς νήματα, χωρίς διεργασίες, χωρίς παραλληλισμό (με την έννοια CPython-with-GIL). Μόνο ένα νήμα ταχυδακτυλουργεί πολλές εργασίες που περνούν τον περισσότερο χρόνο τους περιμένοντας σε δίκτυο / δίσκο / βάση δεδομένων.
Ο ασυγχρονισμός είναι πιο γρήγορος όταν το σημείο συμφόρησης σας περιμένει, όχι υπολογιστές.
Το ελάχιστο βιώσιμο ασύγχρονο πρόγραμμα τριών γραμμών
async def hello()— δηλώνει ένα coroutine. Η κλήση του "hello()" δεν εκτελεί τον κώδικα. δημιουργεί ένα αντικείμενο κορουτίνας.wait asyncio.sleep(1)— αποδίδει τον έλεγχο πίσω στον βρόχο συμβάντος για 1 δευτερόλεπτο.asyncio.run(hello())— δημιουργεί έναν βρόχο συμβάντος και εκτελεί την κορουτίνα μέχρι την ολοκλήρωση.
Κανόνας: `αναμονή` μόνο μέσα στο "async def". Η κλήση "αναμονή" σε μια κανονική συνάρτηση είναι "Σφάλμα Σύνταξης".
Όταν το async κερδίζει (και πότε δεν κερδίζει)
Κέρδισε το Async: Εργασία με δέσμευση εισόδου/εξόδου
Κάθε εργασία που αφιερώνει τον περισσότερο χρόνο του ρολογιού τοίχου σε ΑΝΑΜΟΝΗ είναι υποψήφια για ασυγχρονισμό:
- Αιτήματα HTTP (εξωτερικά API, scraping, webhook)
- Ερωτήματα βάσης δεδομένων
- Το αρχείο διαβάζει / γράφει
- Ροές WebSocket / gRPC
- Καταναλωτές σε ουρά (Redis, RabbitMQ, Kafka)
Παράδειγμα: ανάκτηση 100 διευθύνσεων URL.
Επιτάχυνση ρολογιού τοίχου 50-100x για βαριές εργασίες I/O. Αυτό είναι όπου το async κερδίζει τον προϋπολογισμό πολυπλοκότητάς του.
Ασύγχρονος ΧΑΝΕΙ: Εργασία συνδεδεμένη με CPU
Το Async δεν σας δίνει παραλληλισμό για τον υπολογισμό. Δεδομένου ότι είναι συνεργατικό με ένα νήμα, ένας hot βρόχος CPU μπλοκάρει ολόκληρο τον βρόχο συμβάντος.
Όλες οι άλλες εργασίες εξαφανίζονται ενώ εκτελείται το "pbkdf2". Για εργασίες συνδεδεμένες με CPU, προσεγγίστε το "multiprocessing" ή το "concurrent.futures.ProcessPoolExecutor", όχι το async.
Μικτός φόρτος εργασίας: «run_in_executor».
Εάν ένα βήμα είναι βαρύ για CPU και το υπόλοιπο είναι I/O, τυλίξτε το βήμα της CPU έτσι ώστε να τρέχει σε μια ομάδα νημάτων χωρίς να μπλοκάρετε τον βρόχο:
Το "Κανένα" = προεπιλεγμένο νήμα συγκέντρωσης. Ιδανικό για την κλήση βιβλιοθηκών συγχρονισμού τρίτων που είναι αργές αλλά δεν μπορείτε να ξαναγράψετε.
Τα τέσσερα μοτίβα
1. Διαδοχική — μία εργασία τη φορά
Χρησιμοποιείται όταν κάθε αίτημα εξαρτάται από το αποτέλεσμα του προηγούμενου.
2. asyncio.gather — πυροδοτήστε ταυτόχρονα
Προεπιλεγμένη επιλογή για ανεξάρτητες εργασίες I/O. Αλλά: εάν συγκεντρώσετε 10.000 εργασίες σε ένα API, θα λάβετε περιγραφές αρχείων περιορισμένου ρυθμού ή εξάτμισης. Εκεί μπαίνει το μοτίβο του σηματοφόρου.
3. Semaphore — συγχρονισμός καπακιού
Το asyncio.Semaphore(N) αφήνει το πολύ N εργασίες να περάσουν το asyncio with sem: ανά πάσα στιγμή. Η ουρά των άλλων εργασιών. Χρήση για οποιοδήποτε εξωτερικό API με όριο ρυθμού ή βάση δεδομένων με χώρο συγκέντρωσης συνδέσεων.
4. Λήξη χρονικού ορίου — εγκαταλείψτε την αργή εργασία
Το "asyncio.wait_for" ακυρώνει την υποκείμενη εργασία μετά από N δευτερόλεπτα. Απαραίτητο για οποιονδήποτε κωδικό ασυγχρονισμού που μιλά σε δίκτυο — μην κάνετε ποτέ απεριόριστη αναμονή.
Οι τρεις παγίδες κατάποσης σφαλμάτων
Παγίδα 1: asyncio.gather με return_exceptions=True
Χρήσιμο όταν θέλετε να διατηρήσετε μερικά αποτελέσματα, αλλά θανατηφόρο εάν δεν ελέγχετε κάθε αποτέλεσμα:
Χωρίς τον έλεγχο, τα σφάλματα εξαφανίζονται σιωπηλά.
Παγίδα 2: Φωτιά-και-ξεχάστε εργασίες
Εάν το "background_work()" αυξηθεί, η Python εκπέμπει μια προειδοποίηση κατά τον τερματισμό λειτουργίας και συνεχίζει. Για οτιδήποτε σας ενδιαφέρει, αποθηκεύστε την εργασία και «περιμένετε» ή χρησιμοποιήστε το «asyncio.TaskGroup» (3.11+) που διαδίδει όλα τα σφάλματα.
Παγίδα 3: Συγχρονισμός κώδικα μέσα στο async
Τα "αιτήματα" είναι σύγχρονα. Ακόμη και μέσα σε ένα "async def", το "requests.get" αποκλείει ολόκληρο τον βρόχο μέχρι να φτάσει η απάντηση. Χρησιμοποιήστε το "httpx" (ή το "aiohttp") για ασύγχρονο HTTP.
Κανόνας: μην χρησιμοποιείτε ποτέ μια σύγχρονη βιβλιοθήκη εισόδου/εξόδου μέσα σε ασύγχρονο κώδικα. Εάν η βιβλιοθήκη δεν έχει ασύγχρονη παραλλαγή, τυλίξτε την σε "run_in_executor".
asyncio.TaskGroup — ο τρόπος για να ξεχωρίσετε το 2026
Η Python 3.11 πρόσθεσε το "TaskGroup", το οποίο διορθώνει καθαρά το πρόβλημα πυρκαγιάς και λήξεως:
Δομημένη συγχρονισμός — χωρίς χαμένα σφάλματα, χωρίς ορφανές εργασίες. Προτιμήστε αυτό σε σχέση με το "create_task" στον σύγχρονο κώδικα.
Παράδειγμα πραγματικού κόσμου: scraper περιορισμένης ταχύτητας
Και τα τέσσερα μοτίβα σε 15 γραμμές: οριοθετημένη συγχρονισμός (σηματοφορέας), χρονικά όρια ("wait_for"), ρητά διακλαδώσεις σφάλματος (χωρίς κατάποση) και συλλογή για ανεμιστήρα. Αντιγραφή-επικόλληση αυτού του σχήματος σε οποιαδήποτε εργασία ασύγχρονης εισόδου/εξόδου.
Το Async στην Python έχει μια πραγματική καμπύλη μάθησης, αλλά το νοητικό μοντέλο είναι απλό: ένα νήμα, συνεργατικές παύσεις στο «αναμονή», επικαλύπτονται I/O. Master "gather" + "Semaphore" + "wait_for" + "TaskGroup" και θα έχετε καλύψει το 95% της ασύγχρονης εργασίας που θα γράψετε ποτέ.
Επόμενο βήμα: το Senior Python track έχει 20 πρακτικά μαθήματα για asyncio, TaskGroup, aiohttp/httpx και τα παραπάνω μοτίβα ταυτόχρονης χρήσης — με την πραγματική Python να εκτελείται στο πρόγραμμα περιήγησής σας.