PHP Multi Threading - Синхронизация файла кэша между потоками

Я создал скрипт, который для игровой ситуации пытается найти наилучшее из возможных решений. Он делает это, моделируя каждый возможный ход и количественно оценивая их, решая, таким образом, какой ход лучше сделать (что приведет к самой быстрой победе). Чтобы сделать это быстрее, я реализовал PHP pthread, следующим образом: каждый раз, когда основной поток должен найти возможный ход (назовем это JOB), он вычисляет все возможные ходы на текущей глубине, затем запускает Poolи добавляет к нему каждый возможный ход (назовем это ЗАДАЧЕЙ), поэтому потоки разрабатывают дерево игры для каждого хода отдельно, для всех дополнительных глубин.

Это будет выглядеть примерно так:

(1) Получил новую работу с 10 возможных ходов
(1) Создан новый пул
(1) Добавлены все задания как задачи в пул

(1) Задачи работают одновременно и в результате возвращают целое число, сохраненное в объекте Volatile.

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

Вот как я создаю свои задачи, мой Volatile, и мой Pool:

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 ответов

Другие вопросы по тегам