2016-12-03 14 views
1

Я думал сегодня на работе: есть ли гораздо более быстрый способ получить результаты, используя continue state?php - performance of continue state

for ($i=0; $i<5000; $i++) { 
    if (!($i % 2)) { 
     continue; 
    } 
    do_something_odd($i); 
} 

Быстрее обычный цикл с , если/другое или это быстрее, используя результаты Пропуск продолжить?

Я спрашиваю, потому что производительность и оптимизация.

+3

Это будет очень небольшая разница, поэтому я предпочел бы сосредоточиться на оптимизации вещей, которые на самом деле имеют значение. Тем не менее, если вам просто нужны нечетные числа, вы можете сделать '$ i + 2' вместо' $ i ++ '. – Qirel

+0

@Qirel Я знаю, что для математических циклов вроде '$ i + 2', но я делаю это как пример. Я думаю, когда вы работаете над реальными циклами с множеством данных, много циклов внутри цикла, как mutch будет быстрее и что? –

+0

Собственно, то, что я написал неправильно, синтаксис: '$ i + = 2', а не' $ i + 2'. Хотя, если вы хотите проверить, какой из них быстрее, просто запустите тест. – Qirel

ответ

1

Не уверен, что если вы все еще ищете ответ, в любом случае:

вообще, нет никакой разницы в производительности между:

for (...) { 
    if (condition) continue; 
    some work; 
} 

и

for (...) { 
    if (!condition) some work; 
} 

Я предлагаю, чтобы избежать continue, только потому, что он менее читабель, это в основном goto.

Конечно, первое, что нужно оптимизировать, - это алгоритмы высокого уровня, структура данных и так далее. Если вы сделали это, и вам нужно максимизировать производительность - основным врагом является состояние/ветвь и неверные прогнозы. Есть много различных методов для этого:

  1. Move состояния вне цикла, если это возможно
  2. Split петли на нескольких из них
  3. Обычно умножение, деление и модуль довольно медленно, по сравнению с разрядными мудрыми операторами
  4. Некоторые условия могут быть заменены внеофисных заявления
  5. Un-Rool петли, чтобы минимизировать количество тестов

Мера каждое изменение

Например слегка измененный вариант кода для вычисления количества четных и нечетных чисел в диапазоне [-N, N], за исключением 0:

define('N', 100000000); 

$start = microtime(true); 

$odd_count = 0; 
$even_count = 0; 
for ($i=-N; $i<=N; $i++) 
    if ($i != 0) 
     if ($i % 2 != 0) $odd_count++; 
     else $even_count++; 

$end = microtime(true); 

echo 'odd: '.$odd_count."\n"; 
echo 'even: '.$even_count."\n"; 
echo 'time: '.($end-$start)."\n"; 

Конечно, мы можем заменить весь этот цикл с простой формулой (это алгоритм оптимизации высокого уровня), но позволяет попробовать работать с петлей:

Среднее время на моем хосте на нескольких трасс: 9,1 сек

Применить 1 го и 2-го правила:

for ($i=-N; $i<0; $i++) 
     if ($i % 2 != 0) $odd_count++; 
     else $even_count++; 
for ($i=1; $i<=N; $i++) 
     if ($i % 2 != 0) $odd_count++; 
     else $even_count++; 

Время: 7,7 сек

Применить 3-й и 4-й правило:

for ($i=-N; $i<0; $i++) { 
    $t = $i & 1; 
    $odd_count += $t; 
    $even_count += 1 - $t; 
} 
for ($i=1; $i<=N; $i++) { 
    $t = $i & 1; 
    $odd_count += $t; 
    $even_count += 1 - $t; 
} 

Время: 7,3 сек

И конечный результат:

for ($i=-N; $i<0;) { 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
} 
for ($i=1; $i<=N;) { 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
    $t = $i++ & 1; $odd_count += $t; $even_count += 1 - $t; 
} 

Время: 7.0 сек.

+0

Интересно, в PHP 7 я нахожу, что ваш второй тест быстрее других. Последний тест (7.0) для меня работает 9.57s и 2nd для 8.2s.In PHP5.6 как вы описываете. Интересно! –

+1

@ IvijanStefanStipić возможно, что php7 ввел некоторую оптимизацию, которая сделала 'if%' быстрее, чем '&', или это может быть ошибка, которая сделала '&' медленнее, чем 'if%' :) Я бы попытался использовать '(int)' Кастинг. Во всяком случае, вот почему вы должны все измерить –