我有一个非常昂贵的方法removeColumns(...)
,此外还会被多次调用。所以我想提高它的性能。为了分析优化结果,我使用了两个工具:(1)带有Xdebug Profiler的Webgrind和(2)一个简单的执行时间测量脚本(在PHPUnit测试方法中的命令行上执行):
$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 Profiler的结果:
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
的效果。
这里有什么问题以及如何解决它以获得足够的性能测试结果?
该方法的所有三种变体,我都在优化:
变体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;
}
答案 0 :(得分:0)
这是你的功能打算做的吗?
<?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;
输出:
blacklist:array (
'col1' => 'val1',
'col4' => 'val4',
)
whitelist:array (
'col2' => 'val2',
'col3' => 'val3',
)
但我没有测量表现。你可以在某处上传代码的xdebug输出吗?