PHP-重复操作变得越来越慢

时间:2019-01-04 14:13:34

标签: php

我有一个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脚本允许更多的内存,但是这种情况无济于事。

1 个答案:

答案 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();
    }
}