Κατανεμημένα Συστήματα Σημειώσεις εργαστηρίου Lab#7 - Διεργασίες, Nήματα, Πολυνημάτωση στη Python Νεβράντζας Βάιος-Γερμανός Λάρισα, Φεβρουάριος 2013
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 1 Περίληψη Στο 2ο μέρος του εργαστηριακού μαθήματος θα ασχοληθούμε με θέματα των κατανεμημένων συστημάτων, θεωρητικά και πρακτικά. Τα μαθήματα θα περιλαμβάνουν κάποιες εισαγωγικές έννοιες, ασκήσεις εργαστηρίου και ασκήσεις homework. Αναλυτικά: Έννοιες μαθήματος Ασκήσεις εργαστηρίου Homework
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 2 Notes Έννοιες μαθήματος Στο συγκεκριμένο μέρος των σημειώσεων θα αναλύουμε τις έννοιες που θα συναντήσουμε τόσο στις ασκήσεις εργαστηρίου όσο και στα homeworks. Διεργασία Μια διεργασία είναι ένα πρόγραμμα ή ένα αυτόνομο τμήμα προγράμματος υπό εκτέλεση. Οι όροι πρόγραμμα και διεργασία διαφοροποιούνται από το γεγονός ότι το πρόγραμμα είναι παθητική οντότητα ενώ η διεργασία είναι ενεργητική. Ένας επεξεργαστής (πυρήνας) μπορεί να διαχειρίζεται ταυτόχρονα πολλές διεργασίες, εναλλάσσοντας το ποια εκτελείται κάθε χρονική στιγμή με συνέπεια να υπάρχει ένα είδος (ψευτο)παραλληλισμού. Όταν το σύστημά μας διαθέτει πολλούς πυρήνες τότε ο παραλληλισμός της εκτέλεσης των διεργασιών είναι πραγματικός. Πολλές φορές είναι απαραίτητη η διακοπή κάποιας διεργασίας για να εκτελεστεί κάποια άλλη (έτσι ώστε να εξυπηρετηθούν όλες). Αυτή η εναλλαγή από τη μια διεργασία στην άλλη ονομάζεται μεταγωγή περιβάλλοντος (context switching). Οι πληροφορίες που κρατούνται κατά τη μεταγωγή περιβάλλοντος αφορούν τα ακόλουθα: Από ποια εντολή του προγράμματος πρέπει να συνεχισθεί η εκτέλεση της διεργασίας την επόμενη φορά Ποια είναι η κατάσταση της ΚΜΕ, ώστε να επαναφερθεί για να συνεχιστεί σωστά η εκτέλεση της διεργασίας Ποια είναι τα ενδιάμεσα αποτελέσματα που έχουν υπολογιστεί μέχρι εκείνη τη στιγμή Συνήθως, η κάθε διεργασία έχει στη διάθεσή της ένα κβάντο χρόνου για να εκτελεστεί και μόλις αυτό εκπνεύσει γίνεται εναλλαγή της διεργασίας που εκτελείται από τη ΚΜΕ. Ο κύκλος ζωής μιας διεργασίας φαίνεται στο ακόλουθο σχήμα:
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 3 Νήμα Ένα νήμα εκτέλεσης είναι η μικρότερη ακολουθία προγραμματισμένων εντολών που μπορεί να διαχειρισθεί ανεξάρτητα (από το λειτουργικό σύστημα). Ένα νήμα είναι μια ελαφριά διεργασία. Ένα νήμα συνήθως εμπεριέχεται σε μια διεργασία. Μπορούν να υπάρχουν πολλαπλά νήματα μέσα στην ίδια διεργασία τα οποία μπορούν να μοιράζονται πόρους από το σύστημα (μνήμη, πόρους εισόδου/εξόδου κτλ), ενώ διαφορετικές διεργασίες δεν μπορούν να μοιράζονται τους ίδιους πόρους. Οι διεργασίες έχουν ξεχωριστούς χώρους διευθυνσιοδότησης, ενώ τα νήματα μοιράζονται το σύνολο του χώρου διευθύνσεων που τους παραχωρείται. Έτσι, η εναλλαγή ανάμεσα στα διάφορα νήματα μιας διεργασίας είναι πολύ γρηγορότερη από την εναλλαγή ανάμεσα σε διαφορετικές διεργασίες.
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 4 Πολυνημάτωση είναι η δυνατότητα ενός ΛΣ να υποστηρίξει πολλαπλές εκτελέσεις κώδικα (νήματα) μέσα σε μία διεργασία. Τα νήματα αυτά μοιράζονται τους πόρους της διεργασίας και μπορούν να εκτελούνται ανεξάρτητα. Το πλεονέκτημα ενός πολυνηματικού προγράμματος είναι ότι του επιτρέπει να εκτελείται γρηγορότερα σε υπολογιστικά συστήματα που έχουν πολλούς επεξεργαστές, επεξεργαστές με πολλούς πυρήνες, ή κατά μήκος μιας συστοιχίας υπολογιστών. Python+ Για να δημιουργήσετε προγράμματα με νήματα στη Python θα χρειαστείτε τις παρακάτω εντολές: Το Module threading Το module threading είναι χτισμένο στη κορυφή του παλιού module thread και παρέχει λειτουργικότητα πολυνημάτωσης σε υψήλού επιπέδου μορφή. Μας προσφέρει αρκετές έτοιμες κλάσεις όπως η Thread, η Condition, Event, RLock και η Semaphore. Στα προγράμματά μας θα χρησιμοποιήσουμε τη κλάση Thread, την οποία εισάγουμε με την εντολή: ο κατασκευαστής της κλάσης Thread Για να δημιουργήσουμε ένα νήμα (thread) θα πρέπει να καλέσουμε τον κατασκευαστή της έτοιμης κλάσης Thread που παρέχει το module threading. Η γενική σύνταξη είναι η ακόλουθη: t =
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 5 Πάντα πρέπει να καλούμε τη Thread με τα συγκεκριμένα ορίσματα: name: το όνομα του νήματος, συνήθως της μορφής Thread-N. Μπορεί να παραληφθεί σαν πεδίο. target: είναι το αντικείμενο (συνήθως συνάρτηση) που θα κληθεί για να εκτελεστεί από το νήμα. Αν έχει την τιμή None δεν θα κληθεί τίποτα. args: είναι η πλειάδα ορισμάτων που θα περάσει κατά τη κλήση του αντικειμένου που δείχνουμε με το target. Ως προεπιλογή είναι η κενή πλειάδα ( ). kwargs: είναι ένα λεξικό με τις λέξεις κλειδιά των ορισμάτων που θα περάσουν στο αντικείμενο του target. Ως προεπιλογή είναι το κενό λεξικό { }, μπορεί να παραληφθεί επίσης. Ενεργοποιώντας ένα νήμα - start() Όταν καλούμε τη Thread() το νήμα δημιουργείται αλλά δεν είναι έτοιμο να τρέξει. Για να προκαλέσουμε την εκτέλεσή του θα πρέπει να καλέσουμε τη συνάρτηση start(). Αυτή θα πρέπει να κληθεί το πολύ μία φορά για κάθε νήμα ως εξής: όνομανήματος. start( ) πχ t. start() Περιμένοντας ένα νήμα - join( ) Εάν περιμένουμε ένα νήμα να τελειώσει την εκτέλεση του κώδικά του τότε καλούμε τη συνάρτηση join( ). Αυτή μπλοκάρει το νήμα που την καλεί μέχρι το σημείο που το νήμα για το οποίο καλείται τερματίσει (προσέξτε: όποιο νήμα βάλουμε πρώτο με join() τότε αυτό θα τερματίσει πρώτο). Έτσι, αν γράψουμε μέσα στη main() την εντολή t. join() τότε λέμε στη main να περιμένει τον τερματισμό εκτέλεσης του νήματος t κ μετά να τερματίσει κ αυτή. Επιστροφή συνάρτησης που τρέχει ένα νήμα - η κλάση Queue Όταν μία συνάρτηση δεν επιστρέφει κάτι όταν την εκτελεί κάποιο νήμα (ίσως απλά εκτυπώνει στην οθόνη) τοτε τα πράγματα είναι απλά. Τι γίνεται, όμως, όταν η συνάρτηση που εκτελεί το κάθε διαφορετικό νήμα κάνει return κάποια τιμή; Πως μπορούν τα νήματα να δώσουν την έξοδό τους στο κύριο πρόγραμμα (επικοινωνία νήματος και main());
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 6 Όταν τρέχει ένα νήμα μπορεί να αποθηκεύσει την έξοδο της συνάρτησης σε μία ουρά. Για να το κάνουμε αυτό πρέπει να κάνουμε τα εξής: να εισάγουμε το module queue στην αρχή του πρόγράμματος, να δημιουργήσουμε ένα αντικείμενο της τάξης Queue καλώντας τον κατασκευαστή της τάξης Queue πριν τη δημιουργία των νημάτων να περνάμε στη συνάρτηση που μας ενδιαφέρει να κρατάμε την έξοδό της την ουρά που θα αποθηκεύσουμε τα αποτελέσματά μας την έξοδο, αντί να την κάνουμε return θα πρέπει να την τοποθετούμε στην ουρά καλώντας την συνάρτηση put() τέλος, στη main() θα καλέσουμε τη συνάρτηση get() του αντικειμένου για να βγάλουμε μία μία τις αποθηκευμένες τιμές. Παράδειγμα
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 7 Ασκήσεις εργαστηρίου Οι ασκήσεις εργαστηρίου θα γίνονται την ώρα του μαθήματος. Οι φοιτητές θα πρέπει να τις λύνουν στον υπολογιστή τους (ή στο χαρτί) με τη σειρά, να τις αποθηκεύουν και να τις χρησιμοποιούν ως προεργασία για την επίλυση των Homeworks. #1 Πρόγραμμα σε Python Δημιουργήστε ένα πρόγραμμα στο οποίο θα τρέχουν 2 νήματα τα οποία θα εκτελούν μία συνάρτηση που θα βρίσκει τον μεγαλύτερο ανάμεσα σε 2 ακεραίους. Να γίνει με 2 τρόπους: 1. την εκτύπωση του μεγαλύτερου να την κάνει το κάθε νήμα. 2. την εκτύπωση να την κάνει η main()
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 8 1ος τρόπος
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 9 2ος τρόπος
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 10 #2 Πρόγραμμα σε Python Δημιουργήστε ένα πρόγραμμα το οποίο : θα δημιουργεί μία κενή λίστα με το όνομα threads θα φτιάχνει 10 νήματα τα οποία θα εκτελούν τη συνάρτηση myfunction(). θα προσθέτει το κάθε νήμα στη λίστα threads θα εκκινεί το κάθε νήμα θα χρονομετρεί και θα εκτυπώνει τον συνολικό χρόνο εκτέλεσης Η συνάρτηση myfunction() θα έχει είσοδο τον αριθμό του νήματος, θα αδρανοποιεί (time.sleep())το κάθε νήμα για έναν αριθμό δευτερολέπτων που παράγονται τυχαία στο διάστημα [5,20] και θα εκτυπώνει τη στιγμή που το νήμα θα τελειώνει την εκτέλεση του.
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 11
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 12 #3 Πρόγραμμα σε Python Να γίνει πρόγραμμα το οποίο θα υπολογίζει το άθροισμα της ακολουθίας 1+2+...+Ν, όπου το Ν θα το δίνει ο χρήστης, με 2 τρόπους: 1. χωρίς νήματα στη main() 2. με 2 νήματα με χρήση της συνάρτησης athroisma(): θα υπολογίζει το άθροισμα από α έως β. Το συνολικό άθροισμα θα πρέπει να το εκτυπώνει η main().
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 13
Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python, σελίδα 14 Homeworks Τα homeworks είναι υποχρεωτικά για όλους τους φοιτητές που παρακολουθούν το εργαστηριακό μάθημα και θα πρέπει να στέλνονται ηλεκτρονικά σε.zip μορφή μέσω της πλατφόρμας του E-Class. #1 Να δημιουργήσετε ένα πρόγραμμα στο οποίο: ο χρήστης θα δίνει αρχικά τον αριθμό νημάτων Τ που επιθυμεί να δημιουργηθούν στη συνέχεια θα δίνει τον τελικό όρο Ν το πρόγραμμα θα υπολογίζει και θα εκτυπώνει το άθροισμα S = 1+2+...+(Ν-1)+Ν χρησιμοποιώντας τον αριθμό νημάτων που έδωσε ο χρήστης (διαιρώντας τον προγραμματιστικό φόρτο σε Τ ίσα κομμάτια) αλλά και τον χρόνο που θα έκανε το πρόγραμμα Ιστην ίδια εκτέλεση) χωρίς τη χρήση των νημάτων. Output: