我有一个PHP脚本,可以创建一棵树,其中包含所有可能动作的树,最多可领先15个步骤。
创建移动的脚本如下所示:
function createPossibleMoves($heroId, Hero $Hero, Move $LastPossibleMove = null) {
$moves = array();
foreach ($Hero->Attacks as $attackid => $attack) {
if ($attack['uses'] < 1) continue;
$usesLeft = $attack['uses'];
$LastPerformedMoveIterator = $LastPerformedMove;
while (is_a($LastPerformedMoveIterator, "Move")) {
if ($LastPerformedMoveIterator->heroId == $heroid && $LastPerformedMoveIterator->attackId == $attackid) $usesLeft--;
$LastPerformedMoveIterator = $LastPerformedMoveIterator->PreviousMove;
}
if ($usesLeft < 1) continue;
if ($attack['targets'] === 1) {
foreach ($this->Monsters as $monsterid=>$Monster) {
$Move = new Move($heroid, $attackid, $this, array($monsterid));
$Move->setPreviousMove($LastPerformedMove);
$moves[$Move->getMoveHash()] = $Move;
}
} else {
$maxTargets = $attack['targets'];
if ($maxTargets > count($this->Monsters)) $maxTargets = count($this->Monsters);
$combinations = new Combinations($this->getMonsterIds(), $maxTargets);
foreach ($combinations as $combination) {
$Move = new Move($heroid, $attackid, $this, $combination);
$Move->setPreviousMove($LastPerformedMove);
$moves[$Move->getMoveHash()] = $Move;
}
}
}
}
和Move类的构造函数如下:
public function __construct($heroId, $attackId, Battlefield $Battlefield, $targets) {
$this->Battlefield = clone $Battlefield;
$this->PreviousBattlefield = $Battlefield;
$this->Hero = $this->Battlefield->getHero($heroId);
$this->heroId = $heroId;
$this->attackId = $attackId;
$this->Attack = $this->Hero->getAttack($attackId);
foreach ($targets as $monsterId) {
$this->Targets[] = $this->Battlefield->getMonster($monsterId);
}
$this->targetList = $targets;
}
Battlefield
类持有执行所有动作的战场的单个状态,其中包含所有Monster
实例和所有Hero
实例。克隆Battlefield
时,每个Monster
实例和Hero
实例也都被克隆。
我注意到,当我尝试使用Move
函数创建大约6000-7000个createPossibleMoves
实例时,一开始,大约需要0.0005秒创建一个Move
实例。 ,但最终,这个数量猛增到高达0.1秒/ Move
实例。
这种突然的时间跳跃可能是什么原因?我尝试为该PHP脚本允许更多的内存,但是这种情况无济于事。
答案 0 :(得分:8)
下面的解决方案是尝试取消设置变量,并每进行1000次移动计算就显式调用垃圾回收。
这可能会使您的查询速度降低到5000以下,但应该提高到5000以上,尽管由于您没有提供完整的父类以及Hero和Move类,所以我无法测试此解决方案。
PS:出于对上帝的爱,请注释您的代码,以便任何观察者都能快速了解您的逻辑意图。
function createPossibleMoves($heroId, Hero $Hero, Move $LastPossibleMove = null) {
$moves = array();
foreach ($Hero->Attacks as $attackid => $attack) {
if ($attack['uses'] < 1) continue;
$usesLeft = $attack['uses'];
$LastPerformedMoveIterator = $LastPerformedMove;
while (is_a($LastPerformedMoveIterator, "Move")) {
if ($LastPerformedMoveIterator->heroId == $heroid && $LastPerformedMoveIterator->attackId == $attackid) $usesLeft--;
$LastPerformedMoveIterator = $LastPerformedMoveIterator->PreviousMove;
}
if ($usesLeft < 1) continue;
if ($attack['targets'] === 1) {
foreach ($this->Monsters as $monsterid=>$Monster) {
$Move = new Move($heroid, $attackid, $this, array($monsterid));
$Move->setPreviousMove($LastPerformedMove);
$moves[$Move->getMoveHash()] = $Move;
}
} else {
$maxTargets = $attack['targets'];
if ($maxTargets > count($this->Monsters)) $maxTargets = count($this->Monsters);
$combinations = new Combinations($this->getMonsterIds(), $maxTargets);
foreach ($combinations as $combination) {
$Move = new Move($heroid, $attackid, $this, $combination);
$Move->setPreviousMove($LastPerformedMove);
$moves[$Move->getMoveHash()] = $Move;
}
}
// unset $Move
unset($Move)
// Invoke garbage collection explicitly every 1000 move
if (count($moves) % 1000 == 0) gc_collect_cycles();
}
}