Это не устройство Даффа. Он использует специальный шаг предварительного выравнивания петли (это именно то, что устройство Даффа разработано, чтобы избежать).
В настоящем устройстве Даффа есть один раздел развернутого кода, который изначально частично пропускается switch
. Этот трюк уменьшает необходимое количество кода (только до цикла) и уменьшает количество условных переходов в коде.
Код, который вы представили, представляет собой просто развернутый вручную цикл.
Развертывание петли:
Развертывание цикла - это метод оптимизации, при котором несколько итераций цикла обрабатываются одновременно. Так что вместо:
$number_of_iterations = 128;
for ($n = 0; $n !== $number_of_iterations; ++$n) {
do_something();
}
Вы используете:
$number_of_iterations = 128;
for ($n = 0; $n !== (int)($number_of_iterations / 4); ++$n) {
//Repeat do_something() four times.
//Four is the "unrolling factor".
do_something();
do_something();
do_something();
do_something();
}
Преимущество этого - скорость. Условное ветвление обычно является относительно дорогой операцией. По сравнению с развернутым циклом первый цикл будет проходить через условную ветвь в четыре раз чаще.
К сожалению, такой подход несколько проблематичен. Предположим, что $number_of_iterations
не делится на четыре - разделение труда на более крупные куски больше не будет работать. Традиционное решение этой проблемы - создать еще один цикл, который выполняет работу небольшими порциями, пока оставшийся объем работы не будет выполнен развернутым циклом:
$number_of_iterations = 130;
//Reduce the required number of iterations
//down to a value that is divisible by 4
while ($number_of_iterations % 4 !== 0) {
do_something();
--$number_of_iterations
}
//Now perform the rest of the iterations in an optimised (unrolled) loop.
for ($n = 0; $n !== (int)($number_of_iterations / 4); ++$n) {
do_something();
do_something();
do_something();
do_something();
}
Это лучше, но начальный цикл все равно излишне неэффективен. Он снова разветвляется на каждой итерации - дорогое предложение. В php
это так хорошо, как вы можете получить (??).
Теперь введите устройство Даффа.
Устройство Duffs:
Вместо выполнения жесткой петли перед входом в эффективную развернутую зону, другой альтернативой является прямой переход в развернутую зону, но сначала переход на часть пути через петлю. Это называется устройством Даффа.
Теперь я переключу язык на C
, но структура кода останется очень похожей:
//Note that number_of_iterations
//must be greater than 0 for the following code to work
int number_of_iterations = 130;
//Integer division truncates fractional parts
//counter will have the value which corresponds to the
//number of times that the body of the `do-while`
//will be entered.
int counter = (number_of_iterations + 3) / 4;
switch (number_of_iterations % 4) {
case 0: do { do_something();
case 3: do_something();
case 2: do_something();
case 1: do_something();
while (--counter > 0)
}
Все условные ветви в while ($number_of_iterations % 4 !== 0)
из предыдущих были заменены одним вычисленным переходом (с переключателя).
Весь этот анализ основан на ошибочных представлениях о том, что уменьшение числа условных ветвей в области кода всегда приведет к значительно лучшей производительности, и что компилятор не сможет выполнять такие микро-оптимизация сама по себе, где это необходимо. В современном коде следует избегать как ручного развертывания петли, так и устройства Даффа.