并行计算-搜索算法

深度优先搜索

搜索到叶子结点或所有子树都搜索完时回溯

分支因子(branching factor):每个节点平均的孩子数(b叉树)

DFS搜分支因子为\(b\)深度为\(k\)的树,每个节点遍历一次,时间复杂度为\(O(b^k)\),空间复杂度为\(\Theta(k)\)

并行DFS第一种策略:给每一个处理器一棵子树,\(p=b^k\),前\(k\)层串行搜索,缺点

  • 状态空间树往往不平衡,无结构的特性往往导致静态调度失效
  • 改进方案:让串行搜索深度更深,每个进程就可以处理更多子树(循环分配)

并行DFS关键在于负载:任务分割(splitting)及动态负载均衡

  • 捐赠(donor)进程:发送任务(work)的进程
  • 接受(recipient)进程:接收任务的进程
  • 半分割(half-split):理想地,一个stack被分为两块等大
  • 隔断(cutoff)深度:避免发送太小的任务,在给定深度时就不再发送,自己完成

一些可能的策略:

  • 发送处于栈底的结点:均匀分配搜索空间,低分割开销
  • 发送接近隔断深度的结点:结合强启发式算法会有比较好的性能(尝试分配任务给更有可能包含解的搜索空间)
  • 发送一半在底部和隔断深度之间的结点:对于均匀和不规则搜索空间都非常好

动态负载均衡:

  • 整个空间开始时会被指派给一个处理器
  • 当处理器跑完了它的工作就会从其他处理器获得更多的工作
    • 消息传递机:工作请求与回复
    • 共享地址空间机:锁与工作提取
  • 未探索的状态可以被方便地在处理器中存储为局部栈
  • 一旦一个处理器到达最终状态,所有处理器都会停止

负载均衡策略:设\(V(p)\)为总工作请求数(每个处理器都至少获得一份工作,即\(V(p)\geq p\))

  • 异步轮询(ARR):每个进程维护一个计数器,然后以round-robin方式轮询,最差情况\(V(p)=O(p^2)\)
  • 全局轮询(GRR):系统维护一个全局计数器,然后全局轮询,\(V(p)=p\)
  • 随机轮询(polling):随机请求一个进程给工作,最差情况无界,考虑平均情况\(V(p)=O(p\log p)\)

总开销\(T_o=pW_p-W\)源于(\(W\)为串行工作,\(pW_p\)为并行工作)

  • 通信:请求与发送工作
  • 空闲时间:等待工作
  • 终止检测
  • 共享资源冲突:如GRR的全局计数器
  • 搜索开销因子:\(s=pW_p/W < p\times 1/s\),\(W/W_p<1\)是可能的

优先队列全局or局部

  • 单一优先队列:通信开销太大,访问队列将成为瓶颈,且不具有可扩展性
  • 多优先队列:每个进程维护独立的未检测子问题的优先队列,每个进程都从中取出具有最小下界的继续搜索,并时常将未检测的问题发给其他进程

加速比异常(anomalies):搜索空间是动态生成的,因此实际的工作存在很大区别。

  • 用p个核跑加速比大于p的称为加速异常:一些线程提前完成搜索,剪枝返回
  • 用p个核跑加速比小于p的称为减速异常:目标状态很深,导致大量无效遍历

采用启发式函数作为评估(当前状态到最优状态的距离)

参考资料