2012-12-01 3 views
1

나는 여유 시간을 가지며 응용 프로그램에서 구현할 사용자 정의 로깅 시스템에 대한 몇 가지 옵션을 벤치마킹하기로 결정했습니다. 요점은 실행 중 이벤트를 다른 클래스와 함수에서 나중에 검사 할 수있는 배열로 기록하는 것입니다.특성을 사용하여 다른 클래스의 변수를 변경하면 성능이 저하됩니다.

이것들을 시험해 보는 동안 나는 어리둥절한 것을 보았습니다 : 특성을 사용하여 다른 클래스의 변수를 수정하는 것은 "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... 

답변

1

마침내이 문제를 조사 할만한 시간이 있었으며 해결책은 간단했습니다. 문제는 $TraitUser->doStuff() 대신 $ExternalAppend->doStuff()line 41에 있습니다. 이것을 수정 한 후에 TraitUserTraitUserExternal의 실행 시간은 비슷합니다. $var[] = [$val1, $val2] 대신 $var += [$val1, $val2]을 사용하는 실수도 있지만 차이점에는 영향을 미치지 않습니다. 총 실행 시간 만.

TraitUserTraitUserExternal의 성능이 ExternalAppend에 비해 느린 것은 함수를 호출하고 반환 값을 사용하는 오버 헤드의 합계입니다.

다음 코드는 결과를 확인합니다. 함수를 호출하지 않고 변수를 직접 수정하는 것이 가장 빠릅니다. 함수를 호출하고 변수를 수정하면 두 번째로 빠릅니다. 세 번째 (두 번째 것보다 약간 느린) 방법은 함수에서 반환 된 값으로 변수를 수정하는 것입니다.

네 번째 함수 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 
관련 문제