Haskell tr​​ie 中的 Spaceleak

Posted

技术标签:

【中文标题】Haskell tr​​ie 中的 Spaceleak【英文标题】:Spaceleak in Haskell trie 【发布时间】:2013-04-23 18:16:31 【问题描述】:

我在 Haskell 中编写了一个 trie 实现,但遇到了一些性能问题。我根据http://book.realworldhaskell.org/read/profiling-and-optimization.html 对我的代码进行了相应的分析,并且可以确定问题所在。这是我的 trie 的insertWith 方法:

import qualified Data.Map.Strict as M
-- i have also tried Data.Map.Lazy

data Trie k a = Trie  value  :: !(Maybe a)
                     , childs :: !(Map.Map k (Trie k a))
                     

empty :: Trie a k
empty = Trie Nothing Map.empty

insertWith :: Ord k => (a -> a -> a) -> [k] -> a -> Trie k a -> Trie k a
insertWith f [] a t@(Trie Nothing  _) = t  value = Just a 
insertWith f [] a t@(Trie (Just b) _) = t  value = Just $ f a b 
insertWith f (k:ks) a t = t  childs = m 
    where
        recurse = insertWith f ks a
        m = Map.insertWith (\_ child -> recurse child) k (recurse empty) (childs t)

我的分析代码:

import qualified MyTrie as T
main = do
    let nums = zipWith (\a b -> (show a, b)) [0..100000] [0..]
        trie = foldl' (flip $ uncurry $ T.insertWith (+)) T.empty nums
    putStrLn $ show $ T.lookup "100" trie

分析结果:

 CAF:main4                Main                    113           0    0.0    0.0    55.2   38.3
  main                    Main                    126           0    2.6    0.0    55.2   38.3
   main.trie              Main                    127           0   12.6    2.7    52.6   38.3
    childs                Text.NGram.Trie         137     1000001    0.0    0.0     0.0    0.0
    insertWith            Text.NGram.Trie         135     1123337    3.2    6.2    40.1   35.6
     insertWith.recurse   Text.NGram.Trie         140      123336    0.4    0.0     0.4    0.0
     insertWith.m         Text.NGram.Trie         138     1123334   31.4   29.1    36.4   29.4
      insertWith.recurse  Text.NGram.Trie         142           0    0.0    0.0     0.0    0.0
      insertWith.m.\      Text.NGram.Trie         139      123333    1.5    0.0     5.0    0.3
       insertWith.recurse Text.NGram.Trie         141           0    3.5    0.3     3.5    0.3
        childs            Text.NGram.Trie         143      123333    0.0    0.0     0.0    0.0

   1,403,625,328 bytes allocated in the heap
   1,699,102,256 bytes copied during GC
     393,716,888 bytes maximum residency (11 sample(s))
       4,565,856 bytes maximum slop
             771 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0      2673 colls,     0 par    0.97s    0.98s     0.0004s    0.0027s
  Gen  1        11 colls,     0 par    1.41s    1.41s     0.1285s    0.6767s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.69s  (  0.70s elapsed)
  GC      time    2.38s  (  2.39s elapsed)
  RP      time    0.00s  (  0.00s elapsed)
  PROF    time    0.00s  (  0.00s elapsed)
  EXIT    time    0.06s  (  0.06s elapsed)
  Total   time    3.14s  (  3.15s elapsed)

  %GC     time      75.8%  (75.9% elapsed)

  Alloc rate    2,021,450,981 bytes per MUT second

  Productivity  24.2% of total user, 24.2% of total elapsed

ghc 版本:7.6.2

有人知道如何使 insertWith 方法的性能更好一些吗?

谢谢

【问题讨论】:

最好记下您使用的是什么 GHC 以及如何编译 无法复制。它在 7.6.1 和 7.6.2 中表现良好。你在哪个平台? (而且,你的编译标志是什么?) Arch Linux 64 位内核 3.8.8.1 标志:-O3 -rtsopts -prof -auto-all -caf-all @SvenK 向您正在回复的用户发送地址(就像我在这里所做的那样),因此(s)他会收到回复通知。请注意,没有映射到-O2-O3(还没有)。我仍然无法重现(内核 3.7.10、x86_64、openSuSE 12.3),您可以将您正在运行的确切代码粘贴到某处吗? 【参考方案1】:

insertWith f [] a t@(Trie Nothing  _) = t  value = Just a 
insertWith f [] a t@(Trie (Just b) _) = t  value = Just $ f a b 

af a b 未经评估而被存储。试试

insertWith f [] a t@(Trie Nothing  _) = a `seq` t  value = Just a 
insertWith f [] a t@(Trie (Just b) _) = t  value = Just $! f a b 

【讨论】:

以上是关于Haskell tr​​ie 中的 Spaceleak的主要内容,如果未能解决你的问题,请参考以下文章

Rust 闭包和 Haskell lambda 有啥区别? [关闭]

Haskell 2-3-4 树

parentNode的兼容性问题

VBO/FBO/DisplayLists 如何在 Haskell 的 OpenGL 绑定中工作?

Haskell $ 运算符是不是有逆运算?

IE9中的innerHTML追加