циклы — выполнение состояния продолжения

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

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

Скорее обычная петля с если еще или быстрее пропустить результаты, используя продолжить?

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

1

Решение

Во всяком случае, не уверен, что вы все еще ищете ответ:

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

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

а также

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

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

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

  1. Переместите условие за пределы цикла, если это возможно
  2. Разделить петлю на несколько
  3. Обычно умножение, деление и модуль довольно медленны по сравнению с побитовыми операторами
  4. Некоторые условия можно заменить на операторы без ответвлений
  5. Разверните петли, чтобы минимизировать количество тестов

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

Например, слегка измененная версия вашего кода для вычисления количества четных и нечетных чисел в диапазоне [-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 сек

1

Другие решения

Других решений пока нет …