Middle
Τι είναι ο χρόνος εκτέλεσης (runtime) και πώς λειτουργεί ο προγραμματιστής (scheduler);
sobes.tech AI
Απάντηση από AI
Ο χρόνος εκτέλεσης (runtime) στο Go είναι το περιβάλλον στο οποίο εκτελούνται τα προγράμματα Go. Περιλαμβάνει:
- Διαχείριση μνήμης: Ο συλλέκτης απορριμμάτων (garbage collector) διαχειρίζεται αυτόματα την κατανομή και απελευθέρωση μνήμης.
- Χρονοπρογραμματιστής (scheduler): Διαχειρίζεται την εκτέλεση των goroutines σε νήματα του λειτουργικού συστήματος.
- Κλήσεις συστήματος: Παρέχει μια διεπαφή για αλληλεπίδραση με το λειτουργικό σύστημα.
- Primitive συγχρονισμού: Κανάλια, mutex και άλλα μηχανισμοί για τον συντονισμό των goroutines.
Ο χρονοπρογραμματιστής του Go υλοποιεί το μοντέλο M:N (πολλές goroutines σε πολλά νήματα του λειτουργικού συστήματος). Τα βασικά του συστατικά:
- G (Goroutine): Ένα ελαφρύ νήμα εκτέλεσης, ουσιαστικά μια αφαίρεση πάνω σε μια λειτουργία.
- M (Machine): Ένα νήμα του λειτουργικού συστήματος πάνω στο οποίο εκτελούνται τα προγράμματα Go.
- P (Processor): Ένας λογικός επεξεργαστής που συνδέεται με ένα νήμα του λειτουργικού συστήματος. Διατηρεί μια τοπική ουρά
runnableγια τις goroutines.
Αρχή λειτουργίας του χρονοπρογραμματιστή:
- Οι goroutines (G) δημιουργούνται και προστίθενται σε μια παγκόσμια ή τοπική ουρά
runnable. - Τα νήματα του λειτουργικού συστήματος (M) συσχετίζονται με λογικούς επεξεργαστές (P). Ο αριθμός P είναι προεπιλεγμένα ίσος με τον αριθμό των πυρήνων CPU (
GOMAXPROCS). - Το P παίρνει μια goroutine από την τοπική του ουρά. Αν η τοπική ουρά είναι άδεια, το P προσπαθεί να "κλέψει" (steal) goroutines από την ουρά ενός άλλου P ή από την παγκόσμια ουρά.
- Το M εκτελεί τη goroutine.
- Όταν μια goroutine μπλοκάρει (π.χ., κατά την ανάγνωση από ένα κανάλι χωρίς δεδομένα ή κατά την εκτέλεση μιας κλήσης συστήματος), το M αποσυνδέεται από το P, και το P γίνεται διαθέσιμο για την εκτέλεση άλλης goroutine. Η μπλοκαρισμένη goroutine τίθεται σε αναμονή. Όταν αφαιρεθεί το μπλοκάρισμα, η goroutine γίνεται ξανά
runnableκαι τοποθετείται πίσω στην ουρά. - Αν το M μπλοκάρει σε μια κλήση συστήματος, δεν διατηρεί το P. Μπορεί να δημιουργηθεί ένα νέο M ή να χρησιμοποιηθεί ένα υπάρχον, ώστε το P να συνεχίσει την εκτέλεση άλλων goroutines.
Αυτή η προσέγγιση επιτρέπει την αποδοτική χρήση των πόρων του επεξεργαστή και την εύκολη κλιμάκωση των παράλληλων εργασιών, κρύβοντας την πολυπλοκότητα της διαχείρισης των νήματων του λειτουργικού συστήματος από τον προγραμματιστή.
// Παράδειγμα δημιουργίας μιας goroutine
func myFunc() {
// Κώδικας goroutine
}
func main() {
go myFunc() // Εκκίνηση της goroutine
// Το κύριο πρόγραμμα συνεχίζει την εκτέλεση παράλληλα
}