» » Оптимізація РНР-сценаріїв. Частина 5. Інваріантна оптимізація циклів

Оптимізація РНР-сценаріїв. Частина 5. Інваріантна оптимізація циклів

Інваріантна оптимізація циклів

У будь-якій мові програмування цикл є одним з найголовніших інструментів. Проте використання циклів може привести до помітного уповільнення виконання коду. Щоб продемонструвати це на прикладі, розглянемо сценарій, який приймає рядок і створює новий перетасувати варіант цього рядка.

Один з варіантів вирішення цього завдання показаний нижче.

$shuffled = array();
for($i = 0; $i < (strlen($string)-l); $i++) {
  $shuffled[] = $string[rand(0, (strlen($string)-1))];
}
$new_string = implode($shuffled);


Зверніть увагу на те, що в цьому прикладі для кожної ітерації циклу for викликається функція strlen (). У даному випадку повертається значенням функції strlen () є константа для цього циклу (інваріант), яка вимагає тільки одного обчислення. Метод # 2 прибирає обчислення функції strlen () із циклу, обчислюючи значення один раз і привласнюючи результат змінної:
$str_len = strlen($string) -1 ;
$shuffled = array();
for($i = 0; $i < $str_len; $i++) {
  $shuffled[] = $string[rand(0, $str_len)];
}
$new_string = implode($shuffled) ;


Якщо порівняти час виконання цих двох методів, буде отриманий наступний результат:

Метод № 1 zanяl +0,04446005821228 секунд.
zanяl Метод № 2 +0,035489916801453 секунд.
bиl Спосіб № 2 bиstree метод № 1 20:18%

НА ЗАМІТКУ
У відношенні цього фрагмента коду слід сказати, що кількість часу, витрачений
на виконання сегмента коду, було настільки малим, що отриманий результат виявився не-
точним. Щоб отримати більш точні дані, методи довелося виконувати по 100 разів.


Як бачите, іноді досить видалити з циклу виклик інваріантної функції,
щоб підвищити продуктивність на 20%. Більш того, неможливість виявлення і видалення інваріантів з циклів може істотно знизити продуктивність програми (особливо якщо вони присутні в декількох різних частинах коду).
В даному випадку інваріантне значення було викликано для функції strlen (). Однак майже завжди оптимізувати потрібно будь-яка не скалярний значення, яке використовується всередині циклу. Далі наводиться найпоширеніший приклад організації циклу з використанням значення масиву (припускаючи, що всі змінні визначаються відповідним чином):
$myarray['myvalue'] = 1000001;
for($i = 0; $i < $myarray['myvalue']; $i++) {
  $count++;
}


Хоча функція і не викликається, однак при кожному зверненні до масиву $ myarray необхідно виконувати пошук в хеш-таблиці всередині циклу. Це набагато повільніше, ніж час, необхідний для звернення до скалярним значенням:
$myarray['myvalue'] = 1000001;
$myscalar = $myarray['myvalue1] ;
for($i = 0; $i < $myscalar; $i++) {
  $count++;
}


Якщо порівняти обидва методи, отримаємо наступний результат:
Метод #1 виконувався +0,04446005821228 секунд.
Метод #2 виконувався +0,035489916801453 секунд.
Метод #2 швидше методу #1 на 20,18%
Як бачите, майже 30-відсоткове підвищення продуктивності досягається шляхом присвоювання інваріантного значення масиву скаляру під час роботи циклу (це навіть ще більш вражаючий варіант, ніж при первісній оптимізації strlen ()).


485 12.01.14



Напівжирний Нахилений текст Підкреслений текст Перекреслений текст | Вирівнювання по лівому краю По центру Вирівнювання по правому краю | Вставка смайликів Вибір кольору | Прихований текст Вставка цитати Перетворити вибраний текст з транслітерації в кирилицю Вставка спойлеру