我创建了一个脚本,它针对游戏情况试图找到最佳解决方案。它通过模拟每一个可能的动作并量化它们来做到这一点,从而决定采取哪一个是最好的动作(这将导致最快的胜利)。为了让它更快,我pthread
用下面的方式实现了 PHP 的:每次主线程需要找到一个可能的移动(我们称之为JOB),它计算当前深度中所有可能的移动,然后启动一个Pool
,然后添加到它,每个可能的移动(让我们称之为TASK),因此线程分别为每个移动开发游戏树,用于所有额外的深度。
这看起来像这样:
(1) 获得了一个包含 10 个可能移动的新工作
(1) 创建了一个新池
(1) 将所有工作作为任务添加到池中(1) 任务并发工作,并返回一个整数作为结果,存储在一个 Volatile 对象中
(1) 主线程选择一个动作并执行它
....在 (1) 处重复相同的动作,直到战斗完成
现在,TASKS使用自己的缓存,这意味着在它们工作时,它们会保存缓存并重用它们,但它们之间不会共享缓存,也不会将缓存从一个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);
}
}
这就是我创建任务、myVolatile
和 my 的方式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
,有时,似乎根本没有完成任何工作,就像他们在等待某个线程一样。任何关于可能是什么问题的见解,将不胜感激。