1

自由な時間があったので、アプリケーションに実装するカスタム ログ システムのいくつかのオプションをベンチマークすることにしました。ポイントは、さまざまなクラスや関数からの実行中のイベントを、後で調べることができる配列に単純に記録することです。

これらを試しているうちに、私は困惑したことがわかりました.別のクラスの変数を変更するために特性を使用すると、「自己」の変数を変更するよりも時間がかかります. また、変数を直接変更するよりも時間がかかります。

私はわずかなパフォーマンスの向上にはまったく興味がなく、最終的な実装についてもまだ決定していません。なぜこれが起こるのか、私はただ興味があります。

これをテストするコードは次のとおりです。他のテストもいくつか行いましたが、明らかな理由で遅くなりました。

class ExternalStore {
    public static $log = [];
}

trait LoggerTrait {
    public static function addLog($time, $event) {
        return [$time, $event];
    }
}

echo "<h1>Changing external variable directly</h1>";
class ExternalAppend {
    public function doStuff() {
        for ($i = 0; $i < 100000; $i++) {
            ExternalStore::$log += [microtime(), "Stuff done"];
        }
    }
}

$ExternalAppend = new ExternalAppend;
$start = microtime(true);
$ExternalAppend->doStuff();
$time = microtime(true) - $start;
echo "Execution time: $time<hr>"; // ~0.18...

echo "<h1>Using a trait to change internal variable</h1>";
class TraitUser {
    use LoggerTrait;

    public static $log = [];

    public function doStuff() {
        for ($i = 0; $i < 100000; $i++) {
            self::$log += self::addLog(microtime(), "Stuff done");
        }
    }
}

$TraitUser = new TraitUser();
$start = microtime(true);
$ExternalAppend->doStuff();
$time = microtime(true) - $start;
echo "Execution time: $time<hr>"; // ~0.18...

echo "<h1>Using a trait to change external variable</h1>";
class TraitUserExternal {
    use LoggerTrait;

    public function doStuff() {
        for ($i = 0; $i < 100000; $i++) {
            ExternalStore::$log += self::addLog(microtime(), "Stuff done");
        }
    }
}

$TraitUserExternal = new TraitUserExternal();
$start = microtime(true);
$TraitUserExternal->doStuff();
$time = microtime(true) - $start;
echo "Execution time: $time<hr>"; // ~0.30...
4

1 に答える 1

1

最後に、これを調べる時間があり、解決策は簡単でした。問題はonの代わりに呼び出していました。$ExternalAppend->doStuff()$TraitUser->doStuff()line 41これを修正した後、TraitUserとの実行時間TraitUserExternalは似ています。$var += [$val1, $val2]の代わりに使用する間違いもありますが$var[] = [$val1, $val2]、それは違いに影響を与えないようです。合計実行時間のみ。

TraitUserおよび とTraitUserExternal比較してパフォーマンスが低下するExternalAppendのは、関数の呼び出しと戻り値の使用によるオーバーヘッドの組み合わせによるものです。

次のコードは、調査結果を確認します。関数を呼び出さずに変数を直接変更するのが最も速い方法です。関数を呼び出してそこで変数を変更するのが 2 番目に高速です。3 番目の (2 番目よりわずかに遅い) 方法は、関数から返された値で変数を変更することです。

4 番目の関数doStuff4()は、トレイトを使用して別のクラスの変数を変更するより良い方法も示しています。

<?php
trait Logger {
    protected static function modifyInternalValue($time, $event) {
        self::$internalLog[] = [$time, $event];
    }
    protected static function returnValue($time, $event) {
        return [$time, $event];
    }
    protected static function modifyExternalValue($time, $event) {
        ExternalLogger::$externalLog[] = [$time, $event];
    }
}

class ExternalLogger {
    public static $externalLog = [];

    public static function modifyValue($time, $event) {
        self::$externalLog[] = [$time, $event];
    }

}

class LoggerUser {
    use Logger;

    public static $internalLog = [];
    protected static $iterations = 10000;

    public function doStuff1() {
        echo "<h1>1 - Directly modifying an internal variable</h1>";
        for ($i = 0; $i < self::$iterations; $i++) {
            self::$internalLog[] = [microtime(), "Stuff done"];
        }
    }
    public function doStuff2() {
        echo "<h1>2 - Trait returns a value to internal variable</h1>";
        for ($i = 0; $i < self::$iterations; $i++) {
            self::$internalLog[] = self::returnValue(microtime(), "Stuff done");
        }
    }
    public function doStuff3() {
        echo "<h1>3 - Trait modifies a variable inside a function</h1>";
        for ($i = 0; $i < self::$iterations; $i++) {
            self::modifyInternalValue(microtime(), "Stuff done");
        }
    }
    public function doStuff4() {
        echo "<h1>4 - Trait modifies a variable of an external class</h1>";
        for ($i = 0; $i < self::$iterations; $i++) {
            self::modifyExternalValue(microtime(), "Stuff done");
        }
    }
    public function doStuff5() {
        echo "<h1>5 - External class modifies a variable in itself</h1>";
        for ($i = 0; $i < self::$iterations; $i++) {
            ExternalLogger::modifyValue(microtime(), "Stuff done");
        }
    }
}

function profileFunction($function) {
    $LoggerUser = new LoggerUser();
    $start = microtime(true);
    $LoggerUser->$function();
    $time = microtime(true) - $start;
    echo "Execution time: $time<hr>";
}

profileFunction("doStuff1"); // Fast    | Direct modification
profileFunction("doStuff2"); // Slowest | Function returns a value
profileFunction("doStuff3"); // Slower  | Function modifies a value
profileFunction("doStuff4"); // Slower  | Function modifies external class
profileFunction("doStuff5"); // Slower  | External class modifies itself
于 2012-12-12T12:23:08.370 に答える