Передача значений по ссылкам
Отрицательная сторона передачи значений по ссылкам. Без всякой лирики, прямо: использование ссылок для передачи значений снижает производительность. |
При работе с переменными процессор Zend Engine реализует систему значений с подсчётом ссылок, копировании при записи. Это означает, что многие переменные могут указывать на одно и то же значение. При этом большое количество блоков памяти не потребляется. Рассмотрим пример:
- <?php
- $a = array(1, 2, 3, 4, 5);
- $b = $a;
- ?>
Переменной $b присваивается значение переменной $a, при этом сами данные никуда не копируются! Вместо этого переменная $b преобразуется таким образом, что бы указывать на тоже место в памяти, где хранится переменная $a, т. е. на место хранения первоначально присвоенных данных (в нашем случае это массив со значениями). Процессор отмечает массив и увеличивает счётчик ссылок до 2-х. Рассмотрим ещё один пример:
- <?php
- $a = array(1, 2, 3, 4, 5);
- $b = $a;
- $a[] = 6;
- print_r($a);
- print_r($b);
- ?>
Надеюсь, никто не ждал, что значение переменных окажется одинаковым? :) Шутка. Так что же произошло, если мы тут говорили о ссылках на одно место в памяти? Когда мы начали производить модификацию массива процессор Zend Engine разделяет версии $a и $b. Как только процессор обнаруживает операцию записи по значению, на которую имеется более одной ссылки, происходит копирование данных — создаётся идентичное значение, расположенное в другом участке памяти, никак не связанным с любой другой ссылкой. И только после того как этап копирования при записи будет пройден операция будет продолжена. Такое своевременное дублирование повышает производительность без каких-либо побочных эффектов. И все благодаря исключению копирования ненужных данных!
Однако, все вышесказанное не дает ответа на вопрос «почему же передача по ссылке — зло?».
Во-первых, это бесполезно, т. к. благодаря механизму подсчёта ссылок нет необходимости в передаче переменных по ссылке. Процессор сам будет избегать ненужного копирования при малейшей возможности.
Во-вторых, процессор… так, давайте-ка лучше разберем на примере. Добавим к нашему коду функцию распечатки содержимого:
- <?php
- function prepareArr(&$arr) {
- print count($arr) * 2;
- }
- $a = array(1, 2, 3, 4, 5);
- $b = $a;
- prepareArr($a);
- ?>
Когда процессор приступает к передаче массива $a в функции prepareArr(), он определяет, что значение (наш массив) необходимо передавать по ссылке. Далее обнаруживает, что счётчик ссылок больше 1 (в нашем случае он равен 2). Поскольку значение массива $a передается по ссылке и любые изменения, которые может внести в него наша функция, никак не должны отразиться на $b, процессор делает отдельные копии для массивов $a и $b. При передаче значения переменной в функцию Zeng Engine может просто нарастить счётчик ссылок.
Нанооптимизация, подумаете вы? Может быть, но при передаче значений по ссылке вы теряете 30% производительности этой операции. И чем больше объем данных, с которыми вы работаете, тем больше падает скорость выполнения операции.
Например, выполнение последнего примера в цикле из 50000 итераций составит 0.4538291 сек. Этот же скрипт, но без использования ссылок выполняется за 0.3090010 сек., т. е. на 30% быстрее. Если увеличить объем данных до 6,5 кб, то выполнение циклов с 5000 итераций составим 19.7765129 сек. и 7.3865049 сек. соответственно. Последняя цифра, как вы уже сами догадались, результат выполнения функции без использования ссылок.
В ключе повышения производительности не рекомендуется использовать передачу значений по ссылке. Использование ссылок оправдано только тогда, когда это имеет смысл с функциональной точки зрения.
© habrahabr, автор: iBear
« Назад