Как сделать PHP быстрее: создание строк бесплатное? - PullRequest
3 голосов
/ 21 июля 2009

В этот вопрос представлен бит кода, и спрашивающий хочет ускорить его, исключив использование переменных. Мне кажется, он ищет не в том месте, но это далеко от меня, чтобы знать. Вот код

while ($item = current($data))
{
    echo '<ATTR>',$item, '</ATTR>', "\n";
    next($data);
}

Мне кажется, что воссоздание строк <ATTR> и т. Д. - более одного раза в каждой строке и каждый раз, когда строка обрабатывается - будет связано с затратами (как с точки зрения скорости, так и памяти) , Или, может быть, PHP-процессор достаточно умен, чтобы не допустить того, чтобы строки не помещались в переменные перед циклом?

Я использую переменные для ясности и централизации в любом случае, но: есть ли затраты, связанные с использованием переменных, без использования переменных, или что? (Любой, кто хочет ответить за другие подобные языки, пожалуйста, не стесняйтесь.)

Ответы [ 6 ]

3 голосов
/ 21 июля 2009

Если вы действительно хотите микрооптимизировать таким образом (я не думаю, что это уместно или полезно, кстати - но я понимаю, что это весело ^^), вы можете взглянуть на расширение PHP под названием Vulcan Logic Disassembler

Позволяет получить байт-код, сгенерированный для скрипта PHP.

Затем вы должны использовать такую ​​команду в командной строке, чтобы запустить скрипт:

php -dextension=vld.so -dvld.active=1 tests/temp/temp.php

Например, с помощью этого скрипта:

$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
    echo '<ATTR>',$item, '</ATTR>', "\n";
    next($data);
}

Вы получите этот дамп байт-кода:

line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   8     0  EXT_STMT
         1  INIT_ARRAY                                       ~0      'a'
         2  ADD_ARRAY_ELEMENT                                ~0      'b'
         3  ADD_ARRAY_ELEMENT                                ~0      'c'
         4  ADD_ARRAY_ELEMENT                                ~0      'd'
         5  ASSIGN                                                   !0, ~0
   9     6  EXT_STMT
         7  EXT_FCALL_BEGIN
         8  SEND_REF                                                 !0
         9  DO_FCALL                                      1          'current'
        10  EXT_FCALL_END
        11  ASSIGN                                           $3      !1, $2
        12  JMPZ                                                     $3, ->24
  11    13  EXT_STMT
        14  ECHO                                                     '%3CATTR%3E'
        15  ECHO                                                     !1
        16  ECHO                                                     '%3C%2FATTR%3E'
        17  ECHO                                                     '%0A'
  12    18  EXT_STMT
        19  EXT_FCALL_BEGIN
        20  SEND_REF                                                 !0
        21  DO_FCALL                                      1          'next'
        22  EXT_FCALL_END
  13    23  JMP                                                      ->7
  37    24  RETURN                                                   1
        25* ZEND_HANDLE_EXCEPTION

И с этим скриптом:

$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
    echo "<ATTR>$item</ATTR>\n";
    next($data);
}

Вы получите:

line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
  19     0  EXT_STMT
         1  INIT_ARRAY                                       ~0      'a'
         2  ADD_ARRAY_ELEMENT                                ~0      'b'
         3  ADD_ARRAY_ELEMENT                                ~0      'c'
         4  ADD_ARRAY_ELEMENT                                ~0      'd'
         5  ASSIGN                                                   !0, ~0
  20     6  EXT_STMT
         7  EXT_FCALL_BEGIN
         8  SEND_REF                                                 !0
         9  DO_FCALL                                      1          'current'
        10  EXT_FCALL_END
        11  ASSIGN                                           $3      !1, $2
        12  JMPZ                                                     $3, ->25
  22    13  EXT_STMT
        14  INIT_STRING                                      ~4
        15  ADD_STRING                                       ~4      ~4, '%3CATTR%3E'
        16  ADD_VAR                                          ~4      ~4, !1
        17  ADD_STRING                                       ~4      ~4, '%3C%2FATTR%3E%0A'
        18  ECHO                                                     ~4
  23    19  EXT_STMT
        20  EXT_FCALL_BEGIN
        21  SEND_REF                                                 !0
        22  DO_FCALL                                      1          'next'
        23  EXT_FCALL_END
  24    24  JMP                                                      ->7
  39    25  RETURN                                                   1
        26* ZEND_HANDLE_EXCEPTION

(Этот выход для PHP 5.2.6, который используется по умолчанию в Ubuntu Jaunty)

В конце вы, вероятно, заметите, что различий не так много, и что это часто просто микро -оптимизация ^^

Что может быть более интересным, это посмотреть на различия между версиями PHP: вы могли видеть, что некоторые операции были оптимизированы, например, между PHP 5.1 и 5.2.

Для получения дополнительной информации вы также можете взглянуть на Понимание кодов операций

Веселись!

РЕДАКТИРОВАТЬ: добавить еще один тест:

С этим кодом:

$attr_open = '<ATTR>';
$attr_close = '</ATTR>';
$eol = "\n";

$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
    echo $attr_open, $item, $attr_close, $eol;
    next($data);
}

Вы получаете:

line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
  19     0  EXT_STMT
         1  ASSIGN                                                   !0, '%3CATTR%3E'
  20     2  EXT_STMT
         3  ASSIGN                                                   !1, '%3C%2FATTR%3E'
  21     4  EXT_STMT
         5  ASSIGN                                                   !2, '%0A'
  23     6  EXT_STMT
         7  INIT_ARRAY                                       ~3      'a'
         8  ADD_ARRAY_ELEMENT                                ~3      'b'
         9  ADD_ARRAY_ELEMENT                                ~3      'c'
        10  ADD_ARRAY_ELEMENT                                ~3      'd'
        11  ASSIGN                                                   !3, ~3
  24    12  EXT_STMT
        13  EXT_FCALL_BEGIN
        14  SEND_REF                                                 !3
        15  DO_FCALL                                      1          'current'
        16  EXT_FCALL_END
        17  ASSIGN                                           $6      !4, $5
        18  JMPZ                                                     $6, ->30
  26    19  EXT_STMT
        20  ECHO                                                     !0
        21  ECHO                                                     !4
        22  ECHO                                                     !1
        23  ECHO                                                     !2
  27    24  EXT_STMT
        25  EXT_FCALL_BEGIN
        26  SEND_REF                                                 !3
        27  DO_FCALL                                      1          'next'
        28  EXT_FCALL_END
  28    29  JMP                                                      ->13
  43    30  RETURN                                                   1
        31* ZEND_HANDLE_EXCEPTION

И, с этим (конкатенации вместо ','):

$attr_open = '<ATTR>';
$attr_close = '</ATTR>';
$eol = "\n";

$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
    echo $attr_open . $item . $attr_close . $eol;
    next($data);
}

вы получите:

line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
  19     0  EXT_STMT
         1  ASSIGN                                                   !0, '%3CATTR%3E'
  20     2  EXT_STMT
         3  ASSIGN                                                   !1, '%3C%2FATTR%3E'
  21     4  EXT_STMT
         5  ASSIGN                                                   !2, '%0A'
  23     6  EXT_STMT
         7  INIT_ARRAY                                       ~3      'a'
         8  ADD_ARRAY_ELEMENT                                ~3      'b'
         9  ADD_ARRAY_ELEMENT                                ~3      'c'
        10  ADD_ARRAY_ELEMENT                                ~3      'd'
        11  ASSIGN                                                   !3, ~3
  24    12  EXT_STMT
        13  EXT_FCALL_BEGIN
        14  SEND_REF                                                 !3
        15  DO_FCALL                                      1          'current'
        16  EXT_FCALL_END
        17  ASSIGN                                           $6      !4, $5
        18  JMPZ                                                     $6, ->30
  26    19  EXT_STMT
        20  CONCAT                                           ~7      !0, !4
        21  CONCAT                                           ~8      ~7, !1
        22  CONCAT                                           ~9      ~8, !2
        23  ECHO                                                     ~9
  27    24  EXT_STMT
        25  EXT_FCALL_BEGIN
        26  SEND_REF                                                 !3
        27  DO_FCALL                                      1          'next'
        28  EXT_FCALL_END
  28    29  JMP                                                      ->13
  43    30  RETURN                                                   1
        31* ZEND_HANDLE_EXCEPTION

Так что, разницы почти нет ^^

3 голосов
/ 21 июля 2009

Эй, ребята, вот интересный, мои первоначальные тесты показывают, что сохранение символа новой строки в переменной вместо PHP, разбирающего его с каждой итерацией, быстрее ... См. Ниже

$nl = "\n";
while ($item = current($data))
{
    echo '<ATTR>',$item, '</ATTR>',$nl;
    next($data);
}
2 голосов
/ 21 июля 2009

Кажется, нет никакой измеримой разницы в использовании строковых литералов внутри цикла по сравнению с перемещением их в переменные вне цикла. Я собрал следующий простой скрипт, чтобы проверить это:

$length = 100000;
$data = array();
$totals = array();

for ($i = 0; $i < $length; $i++) {
    $data[] = rand(1,1000);
}

$start = xdebug\_time\_index();
while ($item = current($data))
{
    echo '<ATTR>',$item,'</ATTR>',PHP_EOL;
    next($data);
}
$end = xdebug\_time\_index();
$total = $end - $start;
$totals["Warmup:"] = $total;

reset($data);
$start = xdebug\_time\_index();
while ($item = current($data))
{
    echo '<ATTR>',$item,'</ATTR>',PHP_EOL;
    next($data);
}
$end = xdebug\_time\_index();
$total = $end - $start;
$totals["First:"] = $total;

reset($data);
$startTag = '<ATTR>';
$endTag = '</ATTR>';
$start = xdebug\_time\_index();
while ($item = current($data))
{
    echo $startTag,$item,$endTag,PHP_EOL;
    next($data);
}
$end = xdebug\_time\_index();
$total = $end - $start;
$totals["Second:"] = $total;

foreach ($totals as $label => $data) {
    echo $label,' ', $data,PHP_EOL;
}

Я запускал это несколько раз и не видел заметной разницы между разными методами. На самом деле, иногда разминка была самой быстрой из трех.

Когда вы пытаетесь микрооптимизировать такие вещи, вы действительно измеряете производительность машины, на которой вы работаете, чаще, чем фактический код. Следует отметить, что вы можете захотеть использовать PHP_EOL вместо \n или определить переменную, содержащую такие.

1 голос
/ 21 июля 2009

Если вы действительно хотите ускорить это, используйте вместо этого:

ob_start();
while ($item = current($data))
{
    echo '<ATTR>',$item, '</ATTR>', "\n";
    next($data);
}

Буферизация вывода более эффективно сбрасывает содержимое на клиент, что значительно ускоряет ваш код, чем любая микрооптимизация.

Кроме того, по моему опыту, микрооптимизация - бесполезное занятие, когда дело доходит до кода PHP. Я никогда не видел, чтобы проблемы с производительностью решались путем умного использования определенного метода конкатенации или объявления переменных. Реальные решения, как правило, включают изменения в дизайне или архитектуре или использование менее сложных алгоритмов.

1 голос
/ 21 июля 2009

У всего есть стоимость. Цель состоит в том, чтобы максимально снизить эту стоимость.

Если вы думали о конкатенации, проверьте этот ресурс для получения информации о его производительности. Вероятно, лучше оставить код как есть.

1 голос
/ 21 июля 2009

На самом деле это, вероятно, самая быстрая реализация. Вы можете попытаться объединить все в одну строку, но все операции concat довольно дороги.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...