[PHP] count() + pass-by-reference

yura4773

<?

$file = file('large.txt');

read_file( $file );
echo 'OK';

function read_file( & $file )
{
for ( $ln = 0; $ln < count($file); $ln++ );
}

?>

На файле весом в 300K и длиной 5K строк работает бесконечно долго (запускаю в PHP 5.0.5 (cli) на P4-3G, работает где-то полминуты по субъективным ощущениям). Когда в объявлении функции убираешь "&" - работает неуловимо быстро (заведомо меньше секунды, как и должно быть). В чём прикол? Есть рациональное объяснение, или просто причуды реализации count?

kruzer25

Скорее всего, не причуды реализации count, а хорошая оптимизация интерпретатором в случае без &
А чтобы не полагаться на догадливость интерпретатора, писать надо так:
 function read_file( & $file )
{
$count_of_file=count($file);
for ( $ln = 0; $ln < $count_of_file; $ln++ );
}

Да, и вообще, хороший тон (это, конечно, если ты не хочешь, чтобы в твоём коде можно было разобраться только с твоей помощью) писать определения функций в начале кода.

kruzer25

Да, и ещё, открой для себя time и microtime(true чтобы не писать тут про какие-то "субъективные ощущения", субъективные - они на то и субъективные, что у всех разные %)

alexkravchuk

Скорее всего, не причуды реализации count, а хорошая оптимизация интерпретатором в случае без &
А чтобы не полагаться на догадливость интерпретатора, писать надо так:
Потестировал что-то - проблема именно в count. Причём идентичный эффект наблюдается и в ситуации с глобальными переменными - видимо count плохо работает с данными, которые лежат вне функции. Разница в скорости работы примера, если использовать ссылку или глобальную переменную - в сотни раз относительно передачи переменной по значению, просто при работе с массивом такой разницы в производительности не наблюдается. Интересный эффект, однако.

artimon

http://groups.google.com/group/mailing.www.php-dev/browse_th...
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php
In case you pass it by reference to the function, and then use the same
variable as parameter to a function that doesn\'t accept by reference,
then PHP needs to make a copy of the array. In case you do not pass by
reference, in this case PHP doesn\'t have to copy the array because
it\'s internal refcounting mechanism is smart enough.
If you are just passing by reference to ensure PHP doesn\'t create a
copy, then you\'re doing things wrong. You should only pass by
reference when you are actually modifying the array inside the
function.

yura4773

, спасибо! Как всегда, кратко и информативно.
Только что-то я не понял идеологии в данном случае: объёмистые переменные НЕ надо передавать по ссылке, если мы их не собираемся модифицировать? Т.е. PHP "smart enough", чтобы осуществлять copy-on-write, но при этом в случае фуркций count и strlen (которые по идее и функциями-то быть не должны, а должны бы брать из недр движка готовое значение длины) почему-то происходит копирование содержимого, хотя им, вроде бы, уж совсем незачем внутренне модифицировать свою копию.

kruzer25

Тем не менее, если вызывать count не тысячу раз (для каждого элемента массива а один - эти тормоза для тебя станут совершенно незначительными.
Так что надо сначала учиться писать быстрый код, а потом искать тормоза пхп, а не наоборот - написать ужасный код, и жаловаться на то, что функция, которую вызываешь тысячу раз (хотя мог бы один) работает в десять раз дольше, чем должна.
Оставить комментарий
Имя или ник:
Комментарий: