Τρίτη, 2 Φεβρουαρίου 2016

Σύγκριση αναθεωρήσεων - Γραμμική με Εκθετική Μεταβολή.

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

Στο τμήμα Β κάνουμε κλήση με αναδρομή σε τμήμα (κανονικά δε γίνεται αλλά με την χρήση της εντολής Κλήση που την μετατρέπει σαν κλήση συνάρτησης γίνεται).

Έχουμε λοιπόν την νέα Αναθεώρηση 151 (δεν την δίνω ακόμα στο κεντρικό σημείο "Κώδικας Γλώσσας" για να αντικαταστήσει την 147, γιατί είναι ακόμα υπό έλεγχο, λόγω εκτεταμένων αλλαγών, οπότε μπορεί να την πάρει κανείς από εδώ) όπου έχω χρησιμοποιήσει άλλο τρόπο καταχώρησης μεταβλητών, πινάκων, τμημάτων/συναρτήσεων.

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

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

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

Για την υπό δοκιμή αναθεώρηση 151
Έχουμε λοιπόν για το Α 11246 μια μέση τιμή (τιμή σε χιλιοστά δευτερολέπτου)
Για το Β 10025 μια μέση τιμή, περίπου 12% πιο γρήγορο η κλήση τμήματος

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

Για την τρέχουσα αναθεώρηση 147
Έχουμε λοιπόν για το Α 68544 μια μέση τιμή (τιμή σε χιλιοστά δευτερολέπτου)
Για το Β 120792 μια μέση τιμή, περίπου στο μισό της ταχύτητας του Α, και σε σύγκριση με την αναθεώρηση 151,  12 φορές πιο αργό!

Εκπληκτική διαφορά!
Η εξήγηση είναι ότι
1. Στην  147: Λογικά το Β αργεί σε σχέση με το Α επειδή στο Β οι μεταβλητές γράφονται με μια αρίθμηση σε σχέση με το βάθος κλήσης, ενώ στο Α όλες έχουν το ίδιο όνομα, απλά η ρουτίνα βλέπει πάντα τις νεότερες! Άρα το αλφαριθμητικό στη Β περίπτωση είναι μεγαλύτερο! Και αυτό σημαίνει ότι όταν μεγαλώνει αντιγράφει περισσότερα στοιχεία!
Αν πάμε στις 3000 κλήσεις ο χρόνος στο Β πάει στο 31042 δηλαδή στο 1/4 (φαίνεται ότι έχουμε εκθετική αύξηση όσο περισσότερες κλήσεις κάνουμε).
2. Στην 151: Και στις δυο περιπτώσεις χρησιμοποιούμε πίνακα κατακερματισμού αλλά στην περίπτωση της Α έχουμε ίδια κλειδιά, άρα έχουμε συγκρούσεις! Όμως η αύξηση του πίνακα και στις δυο περιπτώσεις γίνεται τμηματικά και όχι με νέο αντίγραφο.
Αν πάμε στις 3000 κλήσεις ο χρόνος στο Β πάει στο 4926 δηλαδή στο μισό (τα λίγα χιλιοστά τα τρώει ή τα βάζει το σύστημα δεν μετράνε), άρα βλέπουμε ότι έχουμε γραμμική αύξηση όταν αυξάνεται ο όγκος των δεδομένων.

Αναθεώρηση
151: Β:  3.000 κλήσεις 4.926 mSec 6.000 κλήσεις 10.025 mSec  Γραμμική μεταβολή
147: Β:  3.000 κλήσεις 31.042mSec 6.000 κλήσεις 120.792mSec  Εκθετική μεταβολή

το παρακάτω πρόγραμμα δημιουργεί δυο συναρτήσεις μιας γραμμής. που δίνουν περίπου τα παραπάνω αποτελέσματα. Βλέπουμε ότι κάθε μια έχει μια περιγραφή (η εκθετική είναι η Χ**2, θα μπορούσαμε να το γράψουμε και ως Χ^2 είναι το ίδιο στη Μ2000).
Οι σταθερές .00335 και 1.667 μπήκαν για να φέρουν το αποτέλεσμα στο μέγεθος της κάθε περίπτωσης. Αυτό που μας ενδιαφέρει είναι ότι αλλάζοντας το Χ έχουμε περίπου τα ίδια αποτελέσματα. Τότε οι τύποι είναι σωστοί (στη σύγκριση σε διάφορα δεδομένα να έχουμε περίπου ίδια αποτελέσματα, το περίπου εδώ σχετίζεται με μικροδιαφορές που δεν έχουν υπολογιστεί και μπορεί να είναι και εξωτερικοί παράγοντες, που αλλάζουν ελαφρώς το αποτέλεσμα της μέτρησης).

def o1(x)= (x**2)*.00335
Print o1(3000),o1(6000)
def o2(x)=x*1.667
Print o2(3000),o2(6000)



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

Για να τρέξετε τα τεστ αρκεί μια επικόλληση σε δυο διαφορετικά τμήματα. Δώστε Σώσε Τεστ1 και μπορείτε να τα πάρετε πάλι με Φόρτωσε Τεστ1

 (Δοκιμάστε με εντολές στην γραμμή εντολών: Γρήγορα και Γρήγορα! όπως και με Αργά, είναι οι τρεις διαφορετικές ταχύτητες της Μ2000, στο Γρήγορα! δεν βλέπουμε ανανεώσεις οθόνης εκτός αν το θέλουμε με την εντολή Ανανέωση, στο Γρήγορα είμαστε στο κανονικό και στο Αργά αλλάζει τρόπο λειτουργίας, και δίνει η Μ2000 περισσότερες φορές χρόνο στο σύστημα, που καμιά φορά είναι υπέρ...και έρχεται η ταχύτητα στο ίδιο με το Γρήγορα).

Σε ένα τμήμα έστω Α
Αναλυτής
Έλεγχος(6000)
Τύπωσε Φόρτος


Ρουτίνα Έλεγχος(ι)
      Τοπικές α,β,γ,δ, α(30)
      Αν ι<1 Τότε Έξοδος Ρουτίνας
      Τύπωσε 6001-ι
      Έλεγχος(ι-1)
Έξοδος Ρουτίνας



Σε ένα τμήμα έστω Β
Τμήμα Έλεγχος {
      Διάβασε ι
      Τοπικές α,β,γ,δ, α(30)
      Αν ι<1 Τότε Έξοδος
      Τύπωσε 6001-ι
      Κάλεσε Έλεγχος ι-1
}
Αναλυτής
Κάλεσε Έλεγχος 6000
Τύπωσε Φόρτος






Αυτό εδώ είναι πιο τεχνικό ακόμα και το έχω ξεκόψει από τα προηγούμενα!

Οι στατικές μεταβλητές, και στις δυο εκδόσεις είναι εκτός από τις καταχωρήσεις αναγνωριστικών που έχουν να κάνουν με όνομα χώρου (αλφαριθμητικά στην 147-πίνακες κατακερματισμού στη 151), και χρησιμοποιούν ένα πιο γρήγορο τρόπο αποθήκευσης, που εσωτερικά έχει δικό του πίνακα κατακερματισμού, αλλά έχει το μειονέκτημα να μην παίρνει "διπλά" κλειδιά, και για το λόγο αυτό χρησιμοποιώ δικό μου σύστημα (το καλό σύστημα είναι το Collection της VB6, αλλά δεν παίρνει διπλά κλειδιά όπως επίσης δεν παίρνει Types (ή Structs στη C ), αλλά παίρνει αντικείμενα ή Variants (μεταβλητές που μπορεί να είναι οτιδήποτε, αλλά όχι UDT user defined types)..

Κάθε τμήμα όταν το καλούμε "αντιγράφεται" σε ένα αντικείμενο εκτέλεσης και έχει ένα όνομα  (μπορεί να μην είναι το ίδιο με το όνομα που το έχουμε καταχωρημένο ως κώδικας).  Αυτό το αντικείμενο εκτέλεσης αναγνωρίζει ένα όνομα χώρου, που συνήθως έχει να κάνει με το κώδικα που τρέχει ή με κάποιο πρόγονο (που βρίσκεται πιο πίσω στη σειρά κλήσης). Π.χ. ένα νήμα έχει δικό του αντικείμενο εκτέλεσης αλλά έχει όνομα χώρου το όνομα του τμήματος που το δημιούργησε. Οι μεταβλητές, οι πίνακες, και άλλα τμήματα και συναρτήσεις που θα δημιουργηθούν θα έχουν το όνομα χώρου που το αντικείμενο εκτέλεσης χρησιμοποιεί. Οι γενικές μεταβλητές δεν έχουν όνομα χώρου! Έχουν όμως σχετική σειρά δημιουργίας, οπότε αν φτιάξουμε σε ένα αντικείμενο εκτέλεσης μια γενική, τότε αυτή θα φανεί από κει και σε πιο νέο κώδικα (δηλαδή θα σκιάσει τυχόν παλαιότερη γενική, μέχρι να χαθεί αυτή, και η παλιά να μπορεί να χρησιμοποιηθεί).

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

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

Με το όνομα χώρου η Μ2000 κάνει "παιχνίδια" δηλαδή μπορεί να δώσει μια συνάρτηση Α() από ένα τμήμα Β να τρέξει μέσα σε ένα τμήμα Γ ενώ θα νομίζει ότι είναι κώδικας από το  τμήμα Β! Εκεί δηλαδή που γνωρίζουμε τα περάσματα με αναφορά μεταβλητών, τώρα γίνεται να περάσει ένα περιβάλλον σε ένα νέο αντικείμενο εκτέλεσης και σε αυτό να εφαρμοστεί σε ένα νέο αντικείμενο εκτέλεσης που θα μιμείται το αρχικό! Δηλαδή  το τμήμα Γ μπορεί να επιστρέφει διαδοχικά τιμές στο Β και να εκτελεί κώδικα του Β, χωρίς να τερματίσει ως Γ. Αυτό οι απλές διαδικαστικές γλώσσες δεν το κάνουν! υπάρχει παράδειγμα εδώ (από 22 -12-2015, τρέχει κανονικά και στην 151 αναθεώρηση).

Ένας άλλος τρόπος μεταφοράς ονόματος χώρου είναι το πέρασμα με αναφορά συνάρτησης μιας ομάδας. Για να δώσουμε αναφορά σε κλειστή ομάδα πρέπει να την ανοίξουμε πρόσκαιρα με την Για {} και τότε ο διερμηνευτής αποδίδει αυτόματα όνομα χώρου σε όλα τα στοιχεία της ομάδας. Κανονικά η αναφορά συνάρτησης είναι αντιγραφή του κώδικα και η νέα συνάρτηση που δημιουργείται λειτουργικά κάνει ότι και η αρχική. Η διαφορά με τις συναρτήσεις ομάδων είναι ότι δίνουν και το όνομα χώρου μετά τον ορισμό (στον ίδιο χώρο, όπου θα διαβαστεί από το διερμηνευτή), και έτσι η νέα συνάρτηση θα έχει πρόσβαση στις συναρτήσεις, τις μεταβλητές, τους πίνακες και τα τμήματα της ομάδας. Άρα και με αυτόν το τρόπο έχουμε πέρασμα σε αντικείμενο εκτέλεσης, ολόκληρο "πληροφοριακό" σύστημα, όπως είναι μια ομάδα, αλλά με την διαφορά ότι δεν έχουμε το αντικείμενο εκτέλεσης, παρά μόνο τα δεδομένα και το λογισμικό τους. Αντί να δώσουμε αναφορά σε συνάρτηση ομάδας μπορούμε να δώσουμε αναφορά στην ομάδα. Εδώ αν η ομάδα έχει τοπικές μεταβλητές, πίνακες, τμήματα ή και συναρτήσεις, τότε αυτά δεν θα υπάρχουν στο νέο όνομα που θα συνδέεται με την ομάδα. Όμως εσωτερικά αν χρησιμοποιούν κάποια τοπική, θα μπορούν να το κάνουν!

Όλα αυτά δεν έχουν να κάνουν με το πώς καταχωρούμε τις μεταβλητές αλλά πως ο διερμηνευτής εκμεταλλεύεται με χρήση αντικειμένων την υποδομή των μεταβλητών/πινάκων/τμημάτων/συναρτήσεων. Εκεί που είχαμε συναρτήσεις και τμήματα ανά αντικείμενο εκτέλεσης, οι ομάδες έφεραν τις συναρτήσει και τα αντικείμενα ανά όνομα χώρου, ξεφεύγοντας από το αντικείμενο εκτέλεσης. Η χρήση των ομάδων (με υποομάδες και όλα τα σχετικά) μπήκε στην έκδοση 7 η οποία έφτασε  στην 18η αναθεώρηση και μετά έγινε έκδοση 8. Η 8 απέκτησε πολλά νέα πράγματα, όπως δείκτες (αλφαριθμητικά που γράφουν το όνομα της μεταβλητής με το όνομα χώρου) ως ισχνές αναφορές, και έφτασε στην έκδοση 147, όπου αλλάζει με την 151 να είναι μέρος της έκδοσης 8.1 (λόγω του ότι αλλάζω το υποσύστημα και όχι κάτι πιο μεγάλο).


Επίλογος
Με την χρήση πινάκων κατακερματισμού έχει ολοκληρωθεί η Μ2000 σε σχέση με την γραμμική απόκριση στην δημιουργία, αναζήτηση και διαγραφή των μεταβλητών.
Χρειάζεται ακόμα έλεγχος λόγω πληθώρας εντολών και δυνατοτήτων! Πάντως προς το παρόν έχω τρέξει αρκετά παραδείγματα από το Blog και ακόμα δεν βρήκα θέμα. (στην 151). Αλλά ακόμα έχω δουλειά!





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

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