1

我有一些空闲时间,并决定对我将在我的应用程序中实现的自定义日志记录系统的几个选项进行基准测试。关键是在执行期间将来自不同类和函数的事件简单地记录到一个数组中,以便以后检查。

在尝试这些时,我看到了一些让我感到困惑的事情:使用 trait 修改另一个类中的变量比修改“self”中的变量需要更长的时间。它也比直接修改变量需要更长的时间。

我对微不足道的性能提升并不完全感兴趣,也还没有决定最终的实现。我只是好奇为什么会这样。

这是测试它的代码。我还进行了一些其他测试,但由于明显的原因它们速度较慢。

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

终于有时间研究这个问题,解决方案很简单。问题是调用$ExternalAppend->doStuff()而不是$TraitUser->doStuff()on line 41修复此问题后,TraitUser和的执行时间TraitUserExternal相似。使用$var += [$val1, $val2]而不是也有一个错误$var[] = [$val1, $val2],但这似乎不会影响差异。只有总执行时间。

较慢的性能来自调用函数和使用返回值的综合TraitUser开销TraitUserExternalExternalAppend

以下代码证实了调查结果。直接修改变量而不调用任何函数是最快的方法。调用函数并修改变量是第二快的。第三种(比第二种慢一点)方法是使用从函数返回的值修改变量。

第四个函数doStuff4()还显示了使用 trait 修改另一个类中的变量的更好方法。

<?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 回答