【五子棋AI循序渐进】——多线程搜索

      关于多线程搜索,有很多方法来实现,很多文章推荐基于MTD(F)的方式。好处不言而喻,不过我的程序中采用的是基于PVS的多线程搜索。实现起来主要是这几个方面问题需要解决:

1、置换表的互斥访问。

2、局面的复制。

3、线程同步。

逐个说一下这几方面的实现:

1、置换表的互斥访问。

    置换表的作用时保存和读取搜索过的局面。所以使用读写锁即可。代码非常简单,声明一个ReaderWriterLock,在保存置换表时使用写锁,读取时使用读锁。

2、局面复制。

     完整的复制position类,方法有很多,我的代码是创建了一个new函数的重载,然后复制全部值。当然完全可以二进制序列化来创建一个全新对象。这种技术在“3D微观分子模型”一篇中创建球、圆柱模型的副本时使用过。

3、线程同步

     这里涉及到几个方面的问题。

     首先是根节点搜索分离。因为多线程设计时是最基本的从根节点建立线程搜索。根节点搜索函数实际上是一个α-β搜索的简化函数,在程序代码中未使用置换表、内部迭代加深、深度判定等代码,并且将根节点一律视为PV节点处理(不会发生β截断),所以根节点搜索函数只有深度、PV走法两个参数。

     然后是封装搜索函数。因为需要向线程传递多个参数:α、β、PV走法、深度、局面等,所以需要重新封装,以便各个线程搜索中互相独立(不包括共享的置换表)。所以需要建立一个搜索类。

     最后是线程同步。代码现在只写了基础的部分。只是在根节点分离并初始化多个线程搜索类,然后启动全部搜索线程,等待全部线程结束后,按最佳分值找出最佳走法路线进行返回。这里涉及到另一个主要问题,也就是“殊途同归”,这类现象在五子棋中很多,但也不像某些棋类那么多,所以如果能够高效的处理“殊途同归”问题,可以大量减少多线程资源浪费,从而更充分的利用多线程的优势。但是遗憾的是,这部分代码我还么有写。解决“殊途同归”问题,现在的设计思想是使用置换表技术,因为虽然“殊途”,但在“同归”节点上它们就形成了同一局面,这样可以利用置换表技术,当一个线程在搜索时,其他线程就放弃该分支(这意味着需要再定义一个常量和一个调用函数…………因为前几天在优化VCT\VCF逻辑时需要返回路径中断就曾经使用过这种方法,优势是只需要改几行代码),在后续搜索中,搜索该局面的线程会分辨在其分支中这种局面的优劣,优则与其他线程比较,劣则在搜索它的线程中就被淘汰了。所以这种做法是可行的。

    估计这是这系列文章的最后一篇。因为除了一些细节的优化(例如分步或分类生成走法而不一次性生成)暂时还没有新的想法,翻遍了很多参考资料,其中包含了很多近年来一些新的思想和做法,但是绝大多数是与已经应用的技术相同或更落后的一些技术,偶尔看到几篇有启发的研习一番之后发现也都在使用,但属于“殊途同归”,即初衷差不多但是实现角度不同可最终结果基本一致,向“子树复用”技术与正在使用的一项独创启发技术运行过程虽然不相同,但结果基本一致,而且这项启发的复用深度被定义得比“子树复用”要深,而实际实现只有十行代码。

    但是,令人不解的是,即使现在在E5200的CPU上可以达到NPS=80K的程度(如上面所说未优化多线程的“殊途同归”,大约可以比单线程多搜索1层,但非常复杂的局面下甚至没有提高),棋力也不如F6(不开启开局库,而且今天又在的全局VCT中发现了一个问题,真败家)。如果修复了这处错误并且解决多线程“殊途同归”问题再实现了分步生成走法,棋力还与F6棋力相差一些,就非常有必要使用“有害剪裁”和“单步延伸”这样的一些局部搜索方式来解决问题了。

posted @ 2013-09-25 11:16  zcsor~流浪dè风  Views(784)  Comments(0Edit  收藏  举报