Scala Streams性能

时间:2012-02-19 19:44:33

标签: scala functional-programming lazy-evaluation

递归代数数据类型和惰性评估的有用性的典型示例是游戏算法,例如,如John Hughes着名的WhyFP论文所示( Comp.J.,Vol.32,No。2,1989 )。

使用Scala实现它,并对游戏的每个子树使用延迟评估的Stream[Tree[A]],导致trait Tree[A]定义:

sealed trait Tree[A]
case class Branch[A](ts: Stream[Tree[A]]) extends Tree[A]
case class Leaf[A](a: A) extends Tree[A]

现在,一个懒惰评估,可能是无限的游戏可以表示为:

gameTree(b: Board): Tree[Board] = 
  if (b.isAtEndPos) Leaf(b) 
  else Branch(b.emptySlots.toStream.map((pos: Int) => gameTree(b addTic pos)))

您可以实施修剪,评分和并行化策略 实际的算法,例如 minimax 来完成这项工作,以及 评估树的必要部分:

def maximize(tree: Tree[Board]): Int = tree match {
  case Leaf(board) => board.score
  case Branch(subgames) => 
     subgames.map((tree: Tree[Board]) => minimize(tree)).max
} ...
def minimize // symmetrically 

然而,无限流引入了显着的性能损失,使用急切列表(ts: List[Tree[A]])解决相同的游戏树的效率提高了25倍。

在类似的情况下,有没有办法在Scala中有效地使用Streams或lazy结构?

编辑:添加了一些性能结果和实际代码: 在link中是懒惰版本。

懒惰版(scala 2.9.1): Time for gametree creation: 0.031s and for finding the solution 133.216s.

树创建中没有转换,即在 minimax 中的集合上进行映射 Time for gametree creation: 4.791s and for finding the solution 6.088s.

在gameTree创建中转换为列表 Time for gametree creation: 4.438s and for finding the solution 5.601s.

1 个答案:

答案 0 :(得分:4)

如果您希望快速而粗略地了解时间的变化,可以尝试运行:

JAVA_OPTS="-Xprof" scala TicTacToe

正如评论中所述,我无法重现您的体验。