0

Ich habe eine sehr teure Methode removeColumns(...), die zusätzlich mehrmals aufgerufen wird. Also möchte ich seine Leistung steigern. Um die Optimierungsergebnisse zu analysieren wir zwei Werkzeuge: (1) die Xdebug Profiler mit Webgrind und (2) eine einfachen Ausführungszeit Skript Messung (dh innerhalb einer PHPUnit Testmethode auf die Kommandozeile ausgeführt wird):Ergebnisse einer einfachen Überprüfung der Ausführungszeit widersprechen Xdebug Profilergebnissen

$timeStart = microtime(true); 
for ($i=0 ; $i < 1000000; $i++) { 
    // code to measure 
    $this->...->removeColumns($testArray, $columnNames, $isWhitelist); 
} 
$timeStop = microtime(true); 
$resultTime = $timeStop - $timeStart; 
$cycleTime = $resultTime/$i; 
echo number_format($cycleTime, 10, ',', '') . ' sec/run'; 
die(PHP_EOL . '###' . PHP_EOL); 

Aber jetzt schaue ich auf die Ergebnisse - und ich sehe, dass die Ergebnisse der beiden Toas absolut konträr zueinander sind.

Die Ausführungszeit messen Skripts Ergebnisse sind:

variant  sec/run (x69)  sec/run (x1000)  sec/run (x10000) sec/run (x100000) 
1   0,0000121144  0,0000102139  0,0000092316  0,0000089004 
2   0,0000115650  0,0000112779  0,0000098540  0,0000098941 
3   0,0000228260  0,0000240171  0,0000250236  0,0000800230 

difference ms (1-2)  0,0000005494 -0,0000010640 -0,0000006224 -0,0000009937 
yield % (1-2)   4,54%   -10,42%   -6,74%   -11,16% 
difference ms (1-3)  -0,0000107116 -0,0000138032 -0,0000157920 -0,0000711226 
yield % (1-3)   -88,42%   -135,14%  -171,06%  -799,09% 

Wie Sie sehen können, die Optimierung fehlgeschlagen. Wenn die Methode nicht sehr oft aufgerufen wird, wird die Leistung besser, aber je mehr Anrufe, desto schlechter ist es (nicht linear, bis zu 900% Leistungsverluste auf 100.000 Anrufe).

Lassen Sie uns nun die Xdebug Profiler Ergebnisse sehen:

variant XDP-filename XDP-filesize Calls Total Self (ms) Total Inclusive (ms) 
1  1474536556  445,678 KB  69  77325   77403 
2  1474537523  402,208 KB  69  1267   1270 
3  1474539908  402,963 KB  69  2443   2455 

difference ms (1-2)        76058   76133 
yield % (1-2)         98,36%   98,36% 
difference ms (1-3)        74882   74948 
yield % (1-3)         96,84%   96,83% 

Also hier die Leistung der verbesserten Varianten (2 und 3) ist/scheint deutlich besser, als die Leistung des variant 1.

Was ist hier falsch und wie kann es repariert werden, um angemessene Testergebnisse zu erhalten?


die alle drei Varianten des Verfahrens, ich bin zu optimieren:

Variante 1

public function removeColumns(array $table, array $columnNames, bool $isWhitelist = false) 
{ 
    foreach ($table as $rowKey => $row) { 
     if (is_array($row)) { 
      foreach ($row as $fieldName => $fieldValue) { 
       $remove = $isWhitelist 
        ? ! in_array($fieldName, $columnNames) 
        : in_array($fieldName, $columnNames) 
       ; 
       if ($remove) { 
        unset($table[$rowKey][$fieldName]); 
       } 
      } 
     } 
    } 
    return $table; 
} 

Variante 2

public function removeColumns(array $table, array $columnNames, bool $isWhitelist = false) 
{ 
    $tableKeys = array_keys($table); 
    $firstRowKey = $tableKeys[0]; 
    $firstRow = $table[$firstRowKey]; 
    $allColumnNames = array_keys($firstRow); 
    $resultColumns = []; 
    foreach ($allColumnNames as $columnName) { 
     $remain = $isWhitelist 
      ? in_array($columnName, $columnNames) 
      : ! in_array($columnName, $columnNames) 
     ; 
     if($remain) { 
      $resultColumns[$columnName] = array_column($table, $columnName); 
     } 
    } 
    $index = 0; 
    $resultTable = []; 
    foreach ($resultColumns as $resultColumnName => $resultColumn) { 
     foreach ($tableKeys as $index => $tableKey) { 
      $resultTable[$tableKey][$resultColumnName] = $resultColumn[$index]; 
     } 
    } 
    return $resultTable; 
} 

Variante 3

public function removeColumns(array $table, array $columnNames, bool $isWhitelist = false) 
{ 
    $tableKeys = array_keys($table); 
    $firstRowKey = $tableKeys[0]; 
    $firstRow = $table[$firstRowKey]; 
    $allColumnNames = array_keys($firstRow); 
    $columns = []; 
    $i = 0; 
    $arrayMapInputVarNames = []; 
    foreach ($allColumnNames as $columnName) { 
     $remain = 
      ($isWhitelist && in_array($columnName, $columnNames)) || 
      (! $isWhitelist && ! in_array($columnName, $columnNames)) 
     ; 
     if($remain) { 
      $varName = 'column' . $i++; 
      $$varName = $columns[$columnName] = array_column($table, $columnName); 
      $arrayMapInputVarNames[] = '$' . $varName; 
     } 
    } 
    $arrayMapInputString = implode(', ', $arrayMapInputVarNames); 
    eval('$rows = array_map(null, ' . $arrayMapInputString . ');'); 
    foreach ($rows as $index => $row) { 
     $rows[$index] = array_combine(array_keys($columns), array_values($row)); 
    } 
    $table = array_combine(array_keys($table), $rows); 
    return $table; 
} 

Antwort

0

ist das, was Ihre Funktion zu tun beabsichtigt?

<?php 
$table=array(
    'col1'=>'val1', 
    'col2'=>'val2', 
    'col3'=>'val3', 
    'col4'=>'val4' 
); 

$columnNames=array(
    'col2','col3' 
); 

function removeColumns($table, $columnNames, $isWhitelist = false) { 
    if ($isWhitelist) return array_intersect_key($table,array_flip($columnNames)); 
    return array_diff_key($table,array_flip($columnNames)); 
} 

print 'blacklist:'.var_export(removeColumns($table,$columnNames,false),1).PHP_EOL; 
print 'whitelist:'.var_export(removeColumns($table,$columnNames,true),1).PHP_EOL; 

Ausgang:

blacklist:array (
    'col1' => 'val1', 
    'col4' => 'val4', 
) 
whitelist:array (
    'col2' => 'val2', 
    'col3' => 'val3', 
) 

aber ich nicht die Leistung gemessen haben. Könnten Sie die xdebug-Ausgabe Ihres Codes irgendwo hochladen?

Verwandte Themen