PHP多线程-在线程之间同步缓存文件

时间:2019-01-16 11:05:22

标签: php multithreading php-pthread

我创建了一个脚本,该脚本针对游戏情况尝试寻找最佳解决方案。它通过模拟每个可能的动作并对其进行量化,从而确定哪个是最好的动作(这将导致最快的胜利)来做到这一点。为了使其更快,我以以下方式实现了PHP的pthread:每次主线程需要查找可能的移动时(我们将此称为 JOB ),它将计算所有当前深度中的可能动作,然后开始Pool,并向其中添加每个可能的动作(我们称之为 TASK ),因此线程分别为每个动作开发了游戏树,所有其他深度。

这看起来像这样:

  

(1)通过10个可能的动作获得了新工作
  (1)创建了一个新池
  (1)将所有作业作为任务添加到池中

     
    

(1)任务协同工作,并返回一个整数,存储在易失性对象中

  
     

(1)主线程选择一个动作并执行该动作
  ....在(1)重复同样的操作,直到战斗完成

现在,任务使用自己的缓存,这意味着它们在工作时会保存并重新使用缓存,但它们之间不会共享缓存,也不会从服务器上接管缓存。 JOB 转到另一个 JOB 。我尝试解决此问题并以某种方式进行了管理,但我认为这不是预期的方法,因为它会使所有过程变慢。

我试图做的事情如下:创建一个类,该类将所有缓存哈希存储在数组中,然后在创建池之前,将其添加到Volatile对象中。在运行任务之前,它会检索此缓存,并将其用于读/写操作,并在任务完成时将其与Volatile对象中的实例合并。就像在 JOB 1 中创建的缓存一样,可以在 JOB 2 中看到它的工作原理,但是它会使整个过程变得慢得多,当时线程仅使用自己的缓存,该缓存是在构建树时构建的,然后在线程完成时销毁。我做错了吗,还是我想要的东西根本无法实现?这是我的代码:

class BattlefieldWork extends Threaded {
    public $taskId;

    public $innerIterator;
    public $thinkAhead;
    public $originalBattlefield;
    public $iteratedBattlefield;
    public $hashes;

    public function __construct($taskId, $thinkAhead, $innerIterator, Battlefield $originalBattlefield, Battlefield $iteratedBattlefield) {
        $this->taskId = $taskId;
        $this->innerIterator = $innerIterator;
        $this->thinkAhead = $thinkAhead;
        $this->originalBattlefield = $originalBattlefield;
        $this->iteratedBattlefield = $iteratedBattlefield;
    }

    public function run() {
        $result = 0;

        $dataSet = $this->worker->getDataSet();
        $HashClassShared = null;
        $dataSet->synchronized(function ($dataSet) use(&$HashClassShared) {
            $HashClassShared = $dataSet['hashes'];
        }, $dataSet);
        $myHashClass = clone $HashClassShared;

        $thinkAhead = $this->thinkAhead;
        $innerIterator = $this->innerIterator;
        $originalBattlefield = $this->originalBattlefield;
        $iteratedBattlefield = $this->iteratedBattlefield;

        // the actual recursive function that will build the tree, and calculate a quantify for the move, this will use the hash I've created
        $result = $this->performThinkAheadMoves($thinkAhead, $innerIterator, $originalBattlefield, $iteratedBattlefield, $myHashClass);

        // I am trying to retrieve the common cache here, and upload the result of this thread
        $HashClassShared = null;
        $dataSet->synchronized(function($dataSet) use ($result, &$HashClassShared) {
            // I am storing the result of this thread
            $dataSet['results'][$this->taskId] = $result;
            // I am merging the data I've collected in this thread with the data that is stored in the `Volatile` object
            $HashClassShared = $dataSet['hashes'];
            $HashClassShared = $HashClassShared->merge($myHashClass);
        }, $dataSet);
    }
}

这就是我创建任务,VolatilePool的方式:

class Battlefield {
    /* ... */

    public function step() {
      /* ... */
      /* get the possible moves for the current depth, that is 0, and store them in an array, named $moves */

      // $nextInnerIterator, is an int, which shows which hero must take an action after the current move
      // $StartingBattlefield, is the zero point Battlefield, which will be used in quantification
      foreach($moves as $moveid => $move) {
          $moves[$moveid]['quantify'] = new BattlefieldWork($moveid, self::$thinkAhead, $nextInnerIterator, $StartingBattlefield, $this);
      }

      $Volatile = new Volatile();
      $Volatile['results'] = array();
      $Volatile['hashes'] = $this->HashClass;


      $pool = new Pool(6, 'BattlefieldWorker', [$Volatile]);
      foreach ($moves as $moveid => $move) {
          if (is_a($moves[$moveid]['quantify'], 'BattlefieldWork')) {
              $pool->submit($moves[$moveid]['quantify']);
          }
      }

      while ($pool->collect());
      $pool->shutdown();

      $HashClass = $Volatile['hashes'];
      $this->HashClass = $Volatile['hashes'];

      foreach ($Volatile['results'] as $moveid => $partialResult) {
          $moves[$moveid]['quantify'] = $partialResult;
      }

      /* The moves are ordered based on quantify, one is selected, and then if the battle is not yet finished, step is called again */
    }
}

这是我合并两个哈希类的方法:

class HashClass {
    public $id = null;
    public $cacheDir;

    public $battlefieldHashes = array();
    public $battlefieldCleanupHashes = array();
    public $battlefieldMoveHashes = array();

    public function merge(HashClass $HashClass) {
        $this->battlefieldCleanupHashes = array_merge($this->battlefieldCleanupHashes, $HashClass->battlefieldCleanupHashes);
        $this->battlefieldMoveHashes = array_merge($this->battlefieldMoveHashes, $HashClass->battlefieldMoveHashes);

        return $this;
    }
}

我已经对代码的每个部分进行了基准测试,以了解我在哪里浪费时间,但是一切似乎都足够快,不能保证我正在经历的时间增加。我在想的是问题出在Threads上,有时似乎根本没有完成任何工作,就像他们在等待某个线程一样。对于可能存在问题的任何见解,将不胜感激。

0 个答案:

没有答案