Δευτέρα 2 Μαΐου 2016

Αναθεώρηση 225

Σε αυτήν την αναθεώρηση πρόσθεσα ένα νέο αντικείμενο. Για την ώρα το χρησιμοποιώ για να βελτιώσω τους χρόνους εκτέλεσης. Έγιναν και αλλαγές που βελτίωσαν την ταχύτητα όταν χρησιμοποιούμε στατικές μεταβλητές:
Σε ένα τμήμα Α μπορούμε να βάλουμε αυτό. Τη δεύτερη γραμμή, μπορούμε να την αφαιρέσουμε. Κάθε φορά που θα τρέχει το Α η τιμή της Α θα παραμένει η τελευταία, και αν δεν την αλλάξουμε με το Α=1 τότε θα αυξάνεται. Δοκιμάστε το στην αναθεώρηση 224 και δείτε τη διαφορά στην 225.

STATIC A
A=1
PROFILER
FOR I=1 TO 10000 {
      A++
}
PRINT TIMECOUNT, A
B=1
PROFILER
FOR I=1 TO 10000 {
      B++
}
PRINT TIMECOUNT, B
LIST


Με Static A=1 δίνουμε την πρώτη τιμή της Α. (αφαιρούμε την γραμμή  Α=1)
Με Clear στη γραμμή εντολών της Μ2000 σβήνουμε όλες τις στατικές, οπότε η Α ξεκινάει από το 1
Οι στατικές μεταβλητές δηλώνονται σε αυτόν που καλεί το τμήμα. Έτσι αν το τμήμα είναι γενικό (δηλαδή το βλέπουμε με την εντολή Τμήματα ? στην γραμμή εντολών), τότε αν το καλέσουμε από δυο διαφορετικά τμήματα, όπου το ένα είναι έστω το Α1 και το άλλο το Β1 που είναι στο Α1 τότε το Β1 θα έχει δικές του στατικές στο γενικό τμήμα με τις στατικές. Αυτό το σύστημα υπάρχει γιατί στην ουσία η Μ2000 εκτελεί το κάθε τμήμα με ένα αντικείμενο εκτέλεσης, και στο τέλος εκτέλεσης αυτό "παραδίδει" μια λίστα με στατικές (αν υπάρχει). Στην επόμενη εκτέλεση θα βρεθεί η λίστα και θα ξεκινήσει με υπάρχουσες στατικές.

Δεν μπορούμε να έχουμε στατική και τοπική με το ίδιο όνομα. Το βρίσκει η Μ2000 και βγάζει λάθος!
Οι στατικές παλαιότερα δεν μπορούσαν να περαστούν με αναφορά. Στις τελευταίες εκδόσεις γίνεται να περαστούν, αλλά έχουμε το εξής "κόλπο": Ο διερμηνευτής φτιάχνει μια κρυφή τοπική, στην οποία βάζει τη τιμή της στατικής και δίνει αυτή με αναφορά. Στην επιστροφή από τη κλήση, παίρνει την τιμή από τη κρυφή μεταβλητή και την καταχωρεί στην στατική. Στην ουσία έχουμε το λεγόμενο copy in copy out. Τεχνικά οι γενικές και οι τοπικές βρίσκονται σε έναν πίνακα τύπου Hash (έχει Ο(1) σε εύρεση, διαγραφή, και εγγραφή, δηλαδή είναι πολύ γρήγορος). Ακόμα και ίδια ονόματα να έχουμε η εύρεση γίνεται από το τελευταίο που μπήκε στο πίνακα. Έτσι γίνεται η σκίαση. Όταν δίνουμε μια μεταβλητή ως αναφορά τότε σχηματίζεται ένα κλειδί στο πίνακα Hash αλλά δεν δίνεται νέα διεύθυνση/χώρος, αλλά δίνεται αυτό που λέει η αναφορά καθώς και μια σημαία λέει ότι είναι αναφορά. Όταν διαγράφονται οι τοπικές ή οι γενικές που δημιουργήθηκαν σε ένα τμήμα τότε διαγράφεται η μνήμη τους (μηδενίζεται) αλλά όχι σε αυτά που έχουν δηλωθεί ότι είναι αναφορά. Έτσι η μνήμη των μεταβλητών καθαρίζει (αν έχουμε αντικείμενα και έχουμε το τελευταίο δείκτη, τότε καθαρίζουν και αυτά). Οι στατικές μεταβλητές βρίσκονται σε μια λίστα συνδεδεμένη με το τρέχον αντικείμενο εκτέλεσης, και όχι στο πίνακα τύπου Hash. Αυτή η λίστα είναι ένα Collection της VB6 το οποίο είναι και αυτό γρήγορο αλλά διαφορετικού τύπου (μια διπλή συνδεδεμένη λίστα μαζί με ένα δένδρο b-tree για εύρεση με κλειδί). Ουσιαστικά σε Collection τα στοιχεία είναι διάσπαρτα στη μνήμη. Στο πίνακα Hash της Μ2000 έχουμε δυο πίνακες, που μπορούν να διπλασιάζονται (στην αλλαγή μεγέθους έχουμε rehashing το οποίο γίνεται γρήγορα γιατί καταχωρούνται τα ενδιάμεσα αποτελέσματα του Hash αλγόριθμου πάνω στο κλειδί, τα οποία είναι ανεξάρτητα του μεγέθους του πίνακα Hash).

Κάποια στιγμή σκέφθηκα αν θα ήταν προτιμότερο να φτιάξω όλες τις μεταβλητές να συνδέονται σε Collection τοπικά. Έτσι δεν θα υπήρχε μια ενιαία λίστα, αλλά πολλές μικρές. Το πρόβλημα θα ήταν το πώς θα γίνεται η αναφορά. Θα έπρεπε να περαστούν όνομα και λίστα. Τώρα γίνεται το εξής, κατά τη κλήση γράφουμε ένα αλφαριθμητικό που είναι το κλειδί στην ουσία στο πίνακα Hash, αυτή είναι η ισχνή αναφορά. Κατά την εκτέλεση αυτού που καλέσαμε κοιτάει το σύστημα αν υπάρχει και αν ναι φτιάχνει αυτή που ζητάμε ως τοπική με αναφορά σε αυτήν που βρήκε. Ποιο όμως είναι το πραγμαιτκό πρόβλημα με το όνομα και τη λίστα; Ότι για την λίστα (Collection) θα έπρεπε να δώσουμε τον δείκτη της. Αυτό σημαίνει ότι θα δίναμε κανονική αναφορά, και όχι ισχνή, με συνέπεια αν καταχωρηθεί κάπου να κρατάει τη λίστα "Ζωντανή". Σε αντίθεση η ισχνή αναφορά αν κρατηθεί σε πίνακα, δεν πειράζει τον πίνακα Hash. Στην περίπτωση της κανονικής αναφοράς ενδέχεται να πετύχουμε να μην μπορεί ποτέ η λίστα να διαγραφεί γιατί κάτι σε αυτήν έχει ένα δείκτη σε αυτήν! Επίσης με τις πολλές λίστες θα έπρεπε να κάνουμε ότι κάνει και η Javasctript, δηλαδή ψάχνει τη τρέχουσα, αν δεν βρει αυτό που θέλει, πάει παραπάνω, και παραπάνω μέχρι να το βρει. Αυτό στη M2000 θα γίνονταν για τις γενικές μεταβλητές. Αλλά με την χρήση του πίνακα Hash, η εύρεση γίνεται άμεσα, για οποιαδήποτε μεταβλητή, και ο τρόπος που γράφονται στο πίνακα (πάντα στο τέλος) βολεύει όταν τερματίζει ένα τμήμα ή μια συνάρτηση, ή μια ρουτίνα ή μια απλή συνάρτηση (γράφεται όπως η ρουτίνα στο τέλος και την καλούμε με @ στην αρχή), τότε διαγράφεται άμεσα το τμήμα των μεταβλητών που ορίστηκαν (επειδή κρατάει λογαριασμό η Μ2000 στο αντικείμενο εκτέλεσης), Η διαγραφή δεν σημαίνει και απόδοση μνήμης στο σύστημα εκτός αν πέσει κάτω από το μισό η χρήση του πίνακα. Έτσι ο ίδιος χώρος χρησιμοποιείται πολλές φορές κατά τις κλήσεις. Σε άλλες γλώσσες που διαφημίζουν ότι όλα είναι αντικείμενο σημαίνει ότι κάθε φορά που καλούμε κάτι με δέκα τοπικές θα πρέπει να φτιαχτούν δέκα αντικείμενα, να δεσμευτεί μνήμη και μετά να κρατηθούν οι διευθύνσεις τους σε ένα πίνακα (ή στη στοίβα εκτέλεσης). Με το τρόπο αυτό έχουμε γρήγορη εκτέλεση αλλά διάσπαρτα τα στοιχεία στη μνήμη, με συνέπεια να μην δουλεύει καλά η ειδική γρήγορη μνήμη του επεξεργαστή. Παρόλα αυτά σε τέτοιου τύπου χειρισμό μπορούμε να πετύχουμε το yield, δηλαδή το σταμάτημα μιας διαδικασίας, απόδοση τιμών και μετά συνέχιση εκτέλεσης. Στη Μ2000 δεν μπορούμε να το κάνουμε αυτό. Όμως εναλλακτικά μπορούμε να κάνουμε κλήση προς τα πίσω:

Α=100
Χ=5000
Συνάρτηση Ψεύτικη(Νέο Χ) {
// αν βγάλουμε το Νέο θα αλλάξει τιμή στη Χ,
// οπότε στο τέλος θα πάρουμε Χ=10
Α+=Χ
}
Τμήμα ΔεςΤο (&Α()) {
Για ι=1 έως 10
Κάλεσε Α(ι)
Επόμενο ι
}
ΔεςΤο οκν$(&Ψεύτικη())
Τύπωσε Α=155
Τύπωσε Χ=5000

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

Παρόμοιο τρόπο χρησιμοποιούν και οι συναρτήσεις που φτιάχνουμε για γεγονότα. Η διαφορά είναι ότι το όνομα δεν είναι τυχαίο αλλά έχει το όνομα του αντικειμένου που δίνει γεγονότα την κάτω παύλα και το όνομα του γεγονότος (στα COM αντικείμενα που ορίσαμε με την Όρισε και το ΜεΓεγονότα).

Όπως το προηγούμενο αλλά χωρίς τη χρήση οκν$() αλλά με χρήση γενικής συνάρτησης και γενικών μεταβλητών (εδώ δεν θέλει το Νέο Χ γιατί στην ουσία η Χ είναι τοπική). Οι γενικές καθώς και η γενική συνάρτηση θα διαγραφούν στο πέρας εκτέλεσης.
Αν βάζαμε μια Α=Α πριν την Α+=Χ τότε θα φτιάχναμε μια τοπική Α οπότε η γενική Α δεν θα άλλαζε!
Η Α<=Α όμως δεν θα φτιάξει γενική! Ο διερμηνευτής όταν βλέπει το <= τότε ψάχνει για γενική. Ενώ στα += πρώτα κοιτάει αν υπάρχει τοπική και μετά αν υπάρχει γενική, αλλά δεν δημιουργεί μεταβλητή. Μεταβλητές δημιουργούνται όταν δεν υπάρχουν με την εκχώρηση τιμής (με το =), και αν έχουμε δώσει το Γενικό ή Γενικές πριν τότε γίνονται γενικές μεταβλητές. Ακόμα και σε ένα Για ι=1 έως 100 αν θέλουμε να αλλάξει η γενική ι τότε γράφουμε Για ι<=1 έως 100. Στο παράδειγμα τυπώνουμε τη γενική ι. Στους γενικούς πίνακες δεν ισχύει το <= γιατί δεν δημιουργούμε πίνακες με το =, την εκχώρηση τιμής, αλλά με την Πίνακας για τοπικό ή τη Γενική (πχ Γενική Α(2,3)=1 δημιουργούμε γενικό πίνακα Α()). Το Α=(1,2,3,4) θα φτιάξει έναν αυτόματο πίνακα, και εμφανίζεται ως *[mArray] που σημαίνει δείκτης σε αντικείμενο mArray (είναι το αντικείμενο των αυτόματων πινάκων, το οποίο είναι μια παραλλαγή του αντικειμένου Πίνακα, με άλλη διεπαφή - interface)
γενική ι
για ι<=1 έως 10
τύπωσε ι
επόμενο
Τμήμα Δες_Λίστα{
Γενική Α(2,3)=1
Γενική Α=(1,2,3,4)
λίστα
}
Δες_Λίστα

Γενικές Α=100, Χ=5000
Συνάρτηση Γενική Α(Χ) {
Α+=Χ
}
Τμήμα ΔεςΤο (&Β()) {
Για ι=1 έως 10
Κάλεσε Β(ι)
Επόμενο ι
}
ΔεςΤο &Α()
Τύπωσε Α=155
Τύπωσε Χ=5000

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.