Βελτιστοποίηση περιττών πινάκων στην PHP
Ας υποθέσουμε ότι ένας προγραμματιστής έχει την εργασία
να βρει το άθροισμα των ακεραίων αριθμών από 1 έως 100000000.
Ο προγραμματιστής μας έγραψε μια κομψή λύση σε αυτό το πρόβλημα, ως εξής:
<?php
echo array_sum(range(1, 100000000));
?>
Κομψή λύση, έτσι δεν είναι; Σε μια γραμμή και όλα αυτά. Αλλά δεν λειτουργεί! Προσπαθήστε να εκτελέσετε αυτόν τον κώδικα και θα εμφανίσει στην οθόνη ένα σφάλμα ότι ζητήσατε πολύ πολύ μνήμη RAM.
Χμ, 100000000 δεν φαίνεται και τόσο πολύ;
Ή μήπως είναι; Ας μετρήσουμε. Η συνάρτηση range
δημιουργεί έναν πίνακα με 100000000 αριθμούς.
Ας υποθέσουμε ότι η PHP διαθέτει 2 bytes
για κάθε αριθμό - τότε για την αποθήκευση του πίνακα μας θα απαιτηθούν
200000000 bytes, δηλαδή περίπου
200 megabytes μνήμης RAM.
Αλλά στην πραγματικότητα θα απαιτηθεί πολύ περισσότερη
μνήμη RAM λόγω του ότι η PHP έχει
πολύ μεγάλες λειτουργικές απώλειες κατά την αποθήκευση πινάκων.
Για παράδειγμα, στο κείμενο του σφάλματος εμφανίζει
ότι προσπαθώ να διαθέσω 4294967304
bytes - περίπου 4 gigabytes!
Είναι σαφές τώρα γιατί εμφανίζεται το σφάλμα - έχουμε υπερβεί κατά πολύ το επιτρεπόμενο όριο μνήμης.
Δεν είναι τόσο δύσκολο να ξαναγράψουμε το script μας με διαφορετικό τρόπο, που καταναλώνει ελάχιστη μνήμη RAM:
<?php
$sum = 0;
for ($i = 1; $i <= 100000000; $i++) {
$sum += $i;
}
echo $sum;
?>
Ή ακόμα καλύτερα χρησιμοποιούμε μια μαθηματική λύση:
<?php
$n = 1000000;
$sum = $n * ($n + 1) / 2;
echo $sum;
?>
Ένας προγραμματιστής είχε την εργασία να βρει το παραγοντικό ενός δεδομένου αριθμού. Το έλυσε ως εξής:
<?php
$n = 100;
echo array_product(range(1, $n));
?>
Εξηγήστε τι είναι λάθος με αυτόν τον κώδικα. Ξαναγράψτε τον κώδικα σε πιο βελτιστοποιημένο.
Ένας προγραμματιστής είχε την εργασία να βρει
το πλήθος των ψηφίων, με τα οποία μπορούμε
να γράψουμε όλους τους ακέραιους αριθμούς από 1 έως 1000000.
Το έλυσε ως εξής:
<?php
echo strlen(implode('', range(1, 1000000)));
?>
Εξηγήστε τι είναι λάθος με αυτόν τον κώδικα. Ξαναγράψτε τον κώδικα σε πιο βελτιστοποιημένο.
Ένας προγραμματιστής είχε την εργασία να βρει
το πλήθος των αριθμών, που διαιρούνται ακριβώς με το
7, και βρίσκονται σε ένα δεδομένο
διάστημα. Το έλυσε ως εξής:
<?php
$arr = [];
for ($i = 0; $i <= 1000; $i++) {
if ($i % 7 == 0) {
$arr[] = $i;
}
}
echo count($arr);
?>
Εξηγήστε τι είναι λάθος με αυτόν τον κώδικα. Ξαναγράψτε τον κώδικα σε πιο βελτιστοποιημένο.
Ένας προγραμματιστής είχε την εργασία να βρει το άθροισμα των διαιρετών ενός αριθμού. Το έλυσε ως εξής:
<?php
$num = 320;
$divs = [];
for ($i = 0; $i <= $num; $i++) {
if ($num % $i == 0) {
$divs[] = $i;
}
}
echo array_sum($divs);
?>
Εξηγήστε τι είναι λάθος με αυτόν τον κώδικα. Ξαναγράψτε τον κώδικα σε πιο βελτιστοποιημένο.