Arrays Haskell实时更新和查找性能

Arrays Haskell实时更新和查找性能,arrays,performance,haskell,profiling,mutable,Arrays,Performance,Haskell,Profiling,Mutable,我正在编写一个游戏ai(aichallenge.org-Ants),它需要大量更新和引用数据结构。我尝试过数组和映射,但基本问题似乎是每次更新都会创建一个新值,这使得更新速度变慢。如果你移动的时间超过一秒钟,游戏就会启动你,因此应用程序被视为“硬实时”。是否可以在Haskell中获得可变数据结构的性能,或者我应该学习Python,或者用OCaml重写代码 我已经完全重写了蚂蚁的“入门包”。从阵列更改为映射,因为我的测试表明映射更新得更快 我在上运行了配置文件的Maps版本,这表明仅地图更新就占用

我正在编写一个游戏ai(aichallenge.org-Ants),它需要大量更新和引用数据结构。我尝试过数组和映射,但基本问题似乎是每次更新都会创建一个新值,这使得更新速度变慢。如果你移动的时间超过一秒钟,游戏就会启动你,因此应用程序被视为“硬实时”。是否可以在Haskell中获得可变数据结构的性能,或者我应该学习Python,或者用OCaml重写代码

我已经完全重写了蚂蚁的“入门包”。从阵列更改为映射,因为我的测试表明映射更新得更快

我在上运行了配置文件的Maps版本,这表明仅地图更新就占用了大约20%的时间

这里简单演示了阵列更新的速度有多慢

slow_array =
    let arr = listArray (0,9999) (repeat 0)
        upd i ar = ar // [(i,i)]
    in  foldr upd arr [0..9999]
现在评估慢_数组!9999几乎需要10秒!虽然一次应用所有更新会更快,但该示例模拟了实际问题,即每个回合都必须更新阵列,最好是在规划下一回合时每次选择移动时更新阵列


感谢nponeccop和Tener对向量模块的参考。下面的代码相当于我的原始示例,但运行时间为0.06秒,而不是10秒

import qualified Data.Vector.Unboxed.Mutable as V

fast_vector :: IO (V.IOVector Int)
fast_vector = do
  vec <- V.new 10000
  V.set vec 0
  mapM_ (\i -> V.write vec i i) [0..9999]
  return vec

fv_read :: IO Int
fv_read  = do
  v <- fast_vector
  V.read v 9999
导入限定数据.Vector.unbox.Mutable作为V
快速向量::IO(V.IOVector Int)
快速向量=do
向量V.写向量i[0..9999]
返回向量
fv_read::IO Int
fv_read=do

首先,想一想你是否可以改进你的算法。还请注意,默认的
Ants.hs
不是最优的,您需要自己滚动

第二,你应该使用一个工具来找出性能问题所在,而不是依赖于挥手。即使使用函数数据结构,Haskell代码通常也比Python快得多(例如,您可以查看比较示例,速度是Python的10-30倍),因此可能会出错

哈斯克尔很好。有关
ST
,请参见
ST
(状态线程)和库中的可变数组。还可以看看包装。最后,您可以使用数据并行haskell、haskell mpi或加载所有可用的CPU内核,甚至在多台计算机上分配工作

您使用的是编译代码(例如
cabal build
ghc--make
)还是
runhaskell
ghci
?后者是字节码解释器,创建的代码比本机代码编译器慢得多。请参阅-这是构建应用程序的首选方法


还要确保已启用优化(
-O2
和)。请注意,
-O
-O2
可以产生不同的效果,并尝试不同的后端,包括新的LLVM后端(
-fllvm
)。

您基本上要求的是可变数据结构。除了标准库之外,我建议您查找以下内容:

  • 向量:
也就是说,我不确定你是否需要它们。对于不同的数据结构也有简洁的算法。数据的快速替换。映射是此包中的哈希表:

  • 无序集装箱:

一次更新一个元素的数组效率低得令人难以置信,因为每次更新都需要制作整个数组的副本。其他数据结构,如
Map
被实现为树,因此允许对数时间更新。但是,一般来说,一次更新一个元素的功能数据结构通常是次优的,因此您应该尝试后退一步,考虑如何一次实现整个结构的转换,而不是一次更新一个元素

例如,通过在一个步骤中执行所有更新,只需复制一次数组,就可以更高效地编写
slow_数组
示例

faster_array =
    let arr = listArray (0,9999) (repeat 0)
    in  arr // [(i,i) | i <- [0..9999]]
更快的数组=
设arr=listArray(09999)(重复0)

在arr//[(i,i)中|我知道代码是编译的,我已经运行过评测。除了更新数据结构需要30%+的时间外,没有任何启发。查看状态线程,谢谢。编辑问题以反映您使用了评测器,并提供wuth一些示例自包含代码,如果可能的话,速度很慢。我的答案是通用的,并且有一个well书面问题可能会吸引精通性能调整的人。“Haskell中有可能具有可变数据结构的性能吗?”答案是肯定的!Haskell可以做到!无序容器是带有哈希的不可变数据结构。(向量既有可变向量,也有不可变向量)Tener,您有这些“整洁”的参考资料吗算法?@GregO'Keefe-无序容器链接导致了一个非常好的持久化映射实现。否则,Chris Okasaki的论文和后续工作()是一个很好的起点。另请参阅StackExchange上的这个问题:谢谢John,非常好的参考资料。我已经开始了解这些内容,尽管可能需要一些时间!