Προγραμματισμός

3 βήματα για μια αναθεώρηση ασύγχρονου Python

Η Python είναι μία από τις πολλές γλώσσες που υποστηρίζουν κάποιον τρόπο για να γράφετε ασύγχρονα προγράμματα - προγράμματα που εναλλάσσονται ελεύθερα μεταξύ πολλών εργασιών, όλα εκτελούνται ταυτόχρονα, έτσι ώστε καμία εργασία να μην κρατά την πρόοδο των άλλων.

Οι πιθανότητες είναι, ωστόσο, ότι έχετε γράψει κυρίως σύγχρονα προγράμματα Python - προγράμματα που κάνουν μόνο ένα πράγμα τη φορά, περιμένοντας κάθε εργασία να ολοκληρωθεί πριν ξεκινήσετε μια άλλη. Η μετάβαση στο async μπορεί να είναι τρομακτική, καθώς απαιτεί εκμάθηση όχι μόνο νέας σύνταξης, αλλά και νέων τρόπων σκέψης σχετικά με τον κώδικα κάποιου.

Σε αυτό το άρθρο, θα διερευνήσουμε πώς ένα υπάρχον, σύγχρονο πρόγραμμα μπορεί να μετατραπεί σε ασύγχρονο. Αυτό περιλαμβάνει κάτι παραπάνω από απλή διακόσμηση λειτουργιών με σύνταξη async. Απαιτείται επίσης να σκεφτούμε διαφορετικά για το πώς λειτουργεί το πρόγραμμά μας και να αποφασίσουμε αν το async είναι ακόμη μια καλή μεταφορά για το τι κάνει.

[Επίσης στο: Μάθετε συμβουλές και κόλπα της Python από τα βίντεο Smart Python του Serdar Yegulalp]

Πότε να χρησιμοποιείτε το async στο Python

Ένα πρόγραμμα Python ταιριάζει καλύτερα για ασύγχρονο όταν έχει τα ακόλουθα χαρακτηριστικά:

  • Προσπαθεί να κάνει κάτι που δεσμεύεται κυρίως από το I / O ή περιμένοντας να ολοκληρωθεί κάποια εξωτερική διαδικασία, όπως μια μακρά λειτουργία δικτύου που διαβάζεται.
  • Προσπαθεί να κάνει ένα ή περισσότερα από αυτά τα είδη εργασιών ταυτόχρονα, ενώ πιθανώς επίσης χειρίζεται τις αλληλεπιδράσεις χρηστών.
  • Οι εν λόγω εργασίες δεν είναι υπολογιστικά βαριές.

Ένα πρόγραμμα Python που χρησιμοποιεί το νήμα είναι συνήθως ένας καλός υποψήφιος για τη χρήση του async. Τα νήματα στην Python είναι συνεταιριστικά. αποδίδουν ο ένας στον άλλο ανάλογα με τις ανάγκες. Οι εργασίες Async στο Python λειτουργούν με τον ίδιο τρόπο. Επιπλέον, το async προσφέρει ορισμένα πλεονεκτήματα σε σχέση με τα νήματα:

  • ο ασύγχρονος/αναμένω Η σύνταξη διευκολύνει τον εντοπισμό των ασύγχρονων τμημάτων του προγράμματος σας. Αντίθετα, είναι συχνά δύσκολο να πεις με μια ματιά ποια τμήματα μιας εφαρμογής τρέχουν σε ένα νήμα.
  • Επειδή οι εργασίες async μοιράζονται το ίδιο νήμα, τα δεδομένα που έχουν πρόσβαση διαχειρίζονται αυτόματα από το GIL (ο εγγενής μηχανισμός της Python για συγχρονισμό της πρόσβασης σε αντικείμενα). Τα νήματα συχνά απαιτούν πολύπλοκους μηχανισμούς για συγχρονισμό.
  • Οι εργασίες Async είναι ευκολότερες στη διαχείριση και την ακύρωση από τα νήματα.

Η χρήση του async είναι δεν συνιστάται εάν το πρόγραμμα Python έχει τα εξής χαρακτηριστικά:

  • Οι εργασίες έχουν υψηλό υπολογιστικό κόστος - π.χ., εκτελούν μεγάλο αριθμό. Το βαρύ υπολογιστικό έργο αντιμετωπίζεται καλύτερα πολυεπεξεργασία, που σας επιτρέπει να αφιερώσετε ένα σύνολο σκεύη, εξαρτήματα νήμα σε κάθε εργασία.
  • Οι εργασίες δεν επωφελούνται από την παρεμβολή. Εάν κάθε εργασία εξαρτάται από την τελευταία, δεν έχει νόημα να τις κάνετε να εκτελούνται ασύγχρονα. Τούτου λεχθέντος, εάν το πρόγραμμα περιλαμβάνεισκηνικά σειριακών εργασιών, θα μπορούσατε να εκτελέσετε κάθε σετ ασύγχρονα.

Βήμα 1: Προσδιορίστε τα σύγχρονα και ασύγχρονα μέρη του προγράμματος σας

Ο κώδικας ασύγχρονου Python πρέπει να ξεκινά από και να διαχειρίζεται από τα σύγχρονα μέρη της εφαρμογής Python. Για το σκοπό αυτό, η πρώτη σας εργασία κατά τη μετατροπή ενός προγράμματος σε ασύγχρονο είναι να σχεδιάσετε μια γραμμή μεταξύ των τμημάτων συγχρονισμού και ασύγχρονου του κώδικα σας.

Στο προηγούμενο άρθρο μας σχετικά με το async, χρησιμοποιήσαμε μια εφαρμογή web scraper ως απλό παράδειγμα. Τα ασύγχρονα μέρη του κώδικα είναι οι ρουτίνες που ανοίγουν τις συνδέσεις δικτύου και διαβάζονται από τον ιστότοπο - όλα όσα θέλετε να παρεμβάλλετε. Αλλά το μέρος του προγράμματος που ξεκινά όλα αυτά δεν είναι ασύγχρονο. ξεκινά τις εργασίες ασύγχρονης και στη συνέχεια τις κλείνει χαριτωμένα καθώς τελειώνουν.

Είναι επίσης σημαντικό να διαχωρίσετε τυχόνλειτουργία μπλοκαρίσματος από το async και διατηρήστε το στο τμήμα συγχρονισμού της εφαρμογής σας. Η ανάγνωση εισόδου χρήστη από την κονσόλα, για παράδειγμα, αποκλείει τα πάντα, συμπεριλαμβανομένου του βρόχου συμβάντος ασύγχρονου. Επομένως, θέλετε να χειριστείτε την είσοδο χρήστη είτε πριν ξεκινήσετε εργασίες ασύγχρονης είτε μετά την ολοκλήρωσή τους. (Το είναι είναι δυνατόν να χειριστούμε την είσοδο χρήστη ασύγχρονα μέσω πολλαπλών επεξεργασιών ή νήματος, αλλά αυτή είναι μια προχωρημένη άσκηση που δεν θα κάνουμε εδώ.)

Μερικά παραδείγματα λειτουργιών αποκλεισμού:

  • Είσοδος κονσόλας (όπως μόλις περιγράψαμε).
  • Εργασίες που περιλαμβάνουν βαριά χρήση CPU.
  • Χρησιμοποιώντας ώρα. κοιμάται να αναγκάσει μια παύση. Λάβετε υπόψη ότι μπορείτε να κοιμηθείτε μέσα σε μια λειτουργία ασύγχρονης χρήσης asyncio.sleep ως υποκατάστατο του ώρα. κοιμάται.

Βήμα 2: Μετατροπή κατάλληλων συναρτήσεων συγχρονισμού σε λειτουργίες ασύγχρονου

Μόλις μάθετε ποια τμήματα του προγράμματος σας θα εκτελούνται ασύγχρονα, μπορείτε να τα χωρίσετε σε συναρτήσεις (αν δεν το έχετε κάνει ήδη) και να τα μετατρέψετε σε λειτουργίες ασύγχρονου με το ασύγχρονος λέξη-κλειδί. Στη συνέχεια, θα χρειαστεί να προσθέσετε κώδικα στο σύγχρονο τμήμα της εφαρμογής σας, για να εκτελέσετε τον κώδικα ασύγχυσης και να συλλέξετε αποτελέσματα από αυτόν, εάν χρειάζεται.

Σημείωση: Θα θέλατε να ελέγξετε την αλυσίδα κλήσεων κάθε λειτουργίας που έχετε κάνει ασύγχρονη και να βεβαιωθείτε ότι δεν επικαλούνται μια πιθανώς μακροχρόνια λειτουργία ή αποκλεισμό. Οι λειτουργίες Async μπορούν να καλούν απευθείας τις λειτουργίες συγχρονισμού, και εάν αυτή η λειτουργία συγχρονισμού αποκλείει, τότε το κάνει και η συνάρτηση async.

Ας δούμε ένα απλοποιημένο παράδειγμα του τρόπου λειτουργίας μιας μετατροπής συγχρονισμού σε ασύγχρονο. Εδώ είναι το πρόγραμμα «πριν»:

def a_function (): # κάποια ενέργεια συμβατή με ασύγχρονο που διαρκεί λίγο (3): do_stuff () main () 

Αν θέλουμε τρεις περιπτώσεις κάνω πράγματα για να τρέξουμε ως εργασίες ασύγχυσης, πρέπει να γυρίσουμε κάνω πράγματα (και πιθανώς ό, τι αγγίζει) σε κώδικα ασύγχρονου. Εδώ είναι ένα πρώτο πέρασμα στη μετατροπή:

εισαγωγή asyncio async def a_function (): # κάποια συμβατή με ασύγχρονη ενέργεια που διαρκεί λίγο def another_function (): # κάποια λειτουργία συγχρονισμού, αλλά όχι ένα μπλοκάρισμα ενός async def do_stuff (): αναμονή a_function () another_function () async def main () ): task = [] for _ in range (3): tasks.append (asyncio.create_task (do_stuff ())) περιμένετε asyncio.gather (task) asyncio.run (main ()) 

Σημειώστε τις αλλαγές που κάναμεκύριος. Τώρα κύριος χρήσεις ασύγχρονο για να ξεκινήσετε κάθε παρουσία του κάνω πράγματα ως ταυτόχρονη εργασία και στη συνέχεια περιμένει τα αποτελέσματα (asyncio.gather). Μετατρέψαμε επίσης a_function σε μια συνάρτηση async, αφού θέλουμε όλες τις περιπτώσεις a_function για να τρέχετε δίπλα-δίπλα και παράλληλα με άλλες λειτουργίες που χρειάζονται ασύγχρονη συμπεριφορά.

Εάν θέλαμε να προχωρήσουμε ένα βήμα παραπέρα, θα μπορούσαμε επίσης να κάνουμε μετατροπή άλλη_λειτουργία για ασύγχρονο:

async def another_function (): # κάποια συνάρτηση συγχρονισμού, αλλά όχι ένα μπλοκάρισμα ενός async def do_stuff (): wait a_function () waiting a another_function () 

Ωστόσο, κάνονταςάλλη_λειτουργία το ασύγχρονο θα ήταν υπερβολικό, καθώς (όπως έχουμε σημειώσει) δεν κάνει τίποτα που θα εμπόδιζε την πρόοδο του προγράμματός μας. Επίσης, αν κάποιος συγχρονίζει τμήματα του προγράμματος μαςάλλη_λειτουργία, θα πρέπει επίσης να τα μετατρέψουμε σε ασύγχρονο, κάτι που θα μπορούσε να κάνει το πρόγραμμά μας πιο περίπλοκο από ό, τι πρέπει.

Βήμα 3: Δοκιμάστε το πρόγραμμα Python async

Οποιοδήποτε πρόγραμμα με ασύγχρονη μετατροπή πρέπει να δοκιμαστεί πριν τεθεί σε παραγωγή για να διασφαλιστεί ότι λειτουργεί όπως αναμένεται.

Εάν το πρόγραμμά σας έχει μικρό μέγεθος - ας πούμε, μερικές δεκάδες γραμμές περίπου - και δεν χρειάζεται μια πλήρη δοκιμαστική σουίτα, τότε δεν πρέπει να είναι δύσκολο να επαληθεύσετε ότι λειτουργεί όπως προορίζεται. Τούτου λεχθέντος, εάν μετατρέπετε το πρόγραμμα σε ασύγχρονο ως μέρος ενός μεγαλύτερου έργου, όπου μια δοκιμαστική σουίτα είναι ένα τυπικό φωτιστικό, είναι λογικό να γράφετε δοκιμές μονάδας για στοιχεία ασύγχρονου και συγχρονισμού.

Και τα δύο μεγάλα δοκιμαστικά πλαίσια στην Python διαθέτουν πλέον κάποια υποστήριξη ασύγχρονης. Το δικό του Pythonανυπόμονος Το πλαίσιο περιλαμβάνει αντικείμενα δοκιμαστικής θήκης για λειτουργίες ασύγχρονου και pytest προσφορέςpytest-asyncio για τους ίδιους σκοπούς.

Τέλος, όταν γράφετε δοκιμές για στοιχεία ασύγχρονου, θα πρέπει να χειριστείτε την πολύ ασύγχρονη κατάσταση ως προϋπόθεση των δοκιμών. Για παράδειγμα, δεν υπάρχει καμία εγγύηση ότι οι εργασίες ασύγχρονης ολοκλήρωσης θα ολοκληρωθούν με τη σειρά που υποβλήθηκαν. Το πρώτο μπορεί να έρθει τελευταία, και μερικά μπορεί να μην ολοκληρωθούν καθόλου. Τυχόν δοκιμές που σχεδιάζετε για μια συνάρτηση async πρέπει να λαμβάνουν υπόψη αυτές τις δυνατότητες.

Πώς να κάνετε περισσότερα με την Python

  • Ξεκινήστε με το async στο Python
  • Πώς να χρησιμοποιήσετε το asyncio στο Python
  • Πώς να χρησιμοποιήσετε το PyInstaller για να δημιουργήσετε εκτελέσιμα Python
  • Εκμάθηση Cython: Πώς να επιταχύνετε το Python
  • Πώς να εγκαταστήσετε το Python με τον έξυπνο τρόπο
  • Πώς να διαχειριστείτε τα έργα Python με το Poetry
  • Πώς να διαχειριστείτε τα έργα Python με το Pipenv
  • Virtualenv και venv: Εξηγήθηκαν εικονικά περιβάλλοντα Python
  • Το Python virtualenv και το venv κάνουν και δεν πρέπει
  • Η εξήγηση και οι υποεπεξεργασίες Python εξηγούνται
  • Πώς να χρησιμοποιήσετε το πρόγραμμα εντοπισμού σφαλμάτων Python
  • Πώς να χρησιμοποιήσετε το χρονοδιάγραμμα για τον προφίλ κώδικα Python
  • Πώς να χρησιμοποιήσετε το cProfile για να προβάλετε τον κώδικα Python
  • Πώς να μετατρέψετε το Python σε JavaScript (και να επιστρέψετε ξανά)