我是PHPExcel的新手,我已经搜索了谷歌,但没有找到我的具体问题。我发现更新/评估工作表中的公式真的慢。
我有一个非常小的excel文件,我正在做一些非常基本的目标寻求(在PHP中完成目标搜索,在excel表中完成最终结果计算)。我已经准确地工作了,但速度绝对让我伤心。公式计算似乎应该归咎于 - 公式计算/更新如何加速?
不幸的是,我不能发布excel文件的副本,因为内容是我公司的商业秘密,但它并不是什么特别的。公式中的算法非常简单。我能想到的唯一可能产生影响的是,一些细胞依赖链可能有点长(15-ish依赖)。
从下面的输出中可以看出,我们只执行11次迭代以寻找目标,总共需要4-5秒。由于这将是一个AJAX服务,我真的需要它比这更快。
这是非常快速和肮脏的概念证明代码,请耐心等待:
<?php
Stopwatch::start();
$inputFileType = PHPExcel_IOFactory::identify( './example.xlsx' );
var_dump( 'FileType: '.$inputFileType );
Stopwatch::rel( 'identify filetype' );
$objReader = PHPExcel_IOFactory::createReader( $inputFileType );
$objReader->setReadDataOnly( true );
$filterSubset = new ReadFilter( 1, 35, range( 'A', 'J' ));
$objReader->setReadFilter( $filterSubset );
Stopwatch::rel( 'create reader' );
$objPHPExcel = $objReader->load( $inputFileName );
Stopwatch::rel( 'load file' );
$data = $objPHPExcel->getSheetByName( 'Data' );
$inputCell = $data->getCell( 'B9' );
$outputCell = $data->getCell( 'B35' );
Stopwatch::rel( 'get cells' );
goalSeek( $inputCell, $outputCell, '0.10', 1, 5 );
function goalSeek( $inputCell, $outputCell, $targetValue ) {
$cellValue = function() use ( &$outputCell, $precision ) {
return round( $outputCell->getCalculatedValue(), $precision );
};
$setValue = function( $value ) use ( &$inputCell, &$objPHPExcel, $cellValue ) {
$inputCell->setValue( $value );
PHPExcel_Calculation::getInstance( $objPHPExcel )->clearCalculationCache(); // -- clear cache so updates are calculated
Stopwatch::rel( 'goal-seek' );
};
// -- very basic goal seeking psuedo-code
while( $stillHunting ) { // -- outside tolerance
$setValue( $newInputValue );
}
};
class ReadFilter implements PHPExcel_Reader_IReadFilter {
private $_startRow = 0;
private $_endRow = 0;
private $_columns = [];
public function __construct( $startRow, $endRow, $columns ) {
$this->_startRow = $startRow;
$this->_endRow = $endRow;
$this->_columns = $columns;
}
public function readCell( $column, $row, $worksheetName = '' ) {
if( $row >= $this->_startRow && $row <= $this->_endRow ) { // -- valid row
if( in_array( $column, $this->_columns )) { // -- valid column
return true;
}
}
// else (implicit)
return false;
}
}
string 'FileType: Excel2007' (length=19)
array (size=2)
'rel' =>
array (size=17)
'identify' => float 0.008597135543823242
'create reader' => float 0.0001199245452880859
'load file' => float 0.387645959854126
'get cells' => float 5.292892456054688E-5
'goal-seek' => float 0.4194750785827637
'goal-seek2' => float 0.3829901218414307
'goal-seek3' => float 0.3478608131408691
'goal-seek4' => float 0.3471150398254395
'goal-seek5' => float 0.3569440841674805
'goal-seek6' => float 0.378180980682373
'goal-seek7' => float 0.3683559894561768
'goal-seek8' => float 0.3778479099273682
'goal-seek9' => float 0.3664979934692383
'goal-seek10' => float 0.4503841400146484
'_avg' => float 0.2794940630594889
'_untilStop' => float 0.5339441299438477
'total' => float 4.726345062255859
答案 0 :(得分:1)
好的,如果你重新计算相同的公式,但在相关单元格中使用不同的值,可能会加速一个可能的解决方案是解析公式一次,只解析一次,但执行多次。
getCalculatedValue()
调用两种方法;第一个是parseFormula()
,它接受公式作为字符串,并构建一个解析器堆栈(作为数组)执行该公式的步骤;第二个(私有方法,所以你需要在Calculation.php中将其更改为public)是processTokenStack()
,它接受3个参数,即通过调用parseFormula()
生成的标记栈,单元格ID (作为字符串)和单元格对象。
您可能只执行一次parseFormula()步骤,然后为每次迭代调用processTokenStack()
,这将消除除第一次迭代之外的所有语法的解析步骤