私は非常に高価なメソッドremoveColumns(...)
を持っていますが、それはさらに複数回呼び出されます。だから私はそのパフォーマンスを向上させたい。最適化の結果、私は2つのツールを使用し分析するために:(1)Webgrind及び(2)簡単な実行時間を計測するスクリプトとXdebug Profiler(それはPHPUnitのテストメソッド内のコマンドラインで実行されます):単純な実行時間のチェックの結果と矛盾するXdebugのプロファイリング結果
$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);
しかし、今私は結果を見ています - そして、私は、どちらの結果も絶対的に互いに反対であることを見ています。
実行時間測定スクリプトの結果は以下のとおりです。あなたが見ることができるように
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%
は、最適化が失敗しました。メソッドがそれほど頻繁に呼び出されない場合は、パフォーマンスは向上しますが、呼び出しが多いほど、非線形(900%
のパフォーマンスが失われ、100.000
が呼び出されます)。
今度は、Xdebugをプロファイラの結果を見てみましょう:
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%
だからここ改善バリアント(2
と3
)の性能は/ variant 1
のパフォーマンスよりも、著しく良好なようです。
適切なパフォーマンステストの結果を得るためにここで何が問題になっていますか?
方法のすべての3つのバリアント、私は最適化しています:
変種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;
}
バリアント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;
}
バリアント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;
}