【问题标题】:Haskell pauses (seemingly) randomly while generating Fibonacci NumbersHaskell 在生成斐波那契数列时(看似)随机暂停
【发布时间】:2013-12-29 19:32:34
【问题描述】:

我在玩 GHCI,遇到了这个小(对我来说)奇怪。

我试过了:

λ> let fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
λ> fibs

只是想看看小谎言的增长速度有多快,然后玩一下。我认为 Haskell 在计算时显示每个 fib 的方式很酷,因此它很好地展示了懒惰。

但是,当我看到数字墙放大时,列表生成将完全停止的瞬间跳过。通常我会认为它正在计算下一个数字,但它们似乎是随机发生的 - 计算下一个 fib 数字总是只是一个加法,所以永远不应该慢。在一个数字上,ghci 停顿了将近一秒钟。

是什么导致了这些短暂的减速?为什么它们只会发生在特定数字上而不是其他数字上?这不应该总是很快吗?

【问题讨论】:

  • 垃圾回收?我想不出任何其他原因。

标签: performance haskell ghci


【解决方案1】:

这几乎可以肯定是垃圾收集 (GC),可能是更高一代(即主要 GC)。在创建大量长寿命垃圾的情况下,这些可能会导致严重暂停。

如果您想看到这种情况发生,您可以制作一个快速可执行文件并检查:

tmp.hs开头:

module Main where

fibs = 1:1:zipWith (+) fibs (tail fibs)

main = print $ fibs !! 100000

使用ghc -rtsopts tmp.hs编译

使用./tmp +RTS -s运行

     454,847,088 bytes allocated in the heap
     230,044,816 bytes copied during GC
       4,291,856 bytes maximum residency (226 sample(s))
      18,080,904 bytes maximum slop
              56 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0       676 colls,     0 par    0.07s    0.07s     0.0001s    0.0023s
  Gen  1       226 colls,     0 par    0.27s    0.28s     0.0012s    0.0084s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.14s  (  0.14s elapsed)
  GC      time    0.34s  (  0.35s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    0.48s  (  0.49s elapsed)

  %GC     time      71.0%  (71.6% elapsed)

  Alloc rate    3,303,664,644 bytes per MUT second

  Productivity  28.9% of total user, 28.8% of total elapsed

这表示 676 次次要垃圾回收和 226 次主要垃圾回收,第二代垃圾回收的完成时间比次要多约 12 倍。请注意,这只是第 10 万个数字,因此数字越大,停顿时间可能会更长。另请注意,GHCI 是一个解释器,因此会有相关的减速。

顺便说一句,我确实尝试在打开优化的情况下编译和运行这个示例。时间上没有明显差异,内存/GC特性几乎相同。

【讨论】:

  • 你是用 -O2 标志编译的吗?
  • 被接受,因为它还展示了你是如何计算出来的,并展示了“证明”。感谢您的出色回答。
  • 如底部所述,我尝试了有无。没有明显差异(-O2 花费了 0.01 秒……),并且 GC 调用的数量相同。
  • @sortfiend 谢谢!这是我的荣幸。
【解决方案2】:

正如上面 Jan Dvorak 所评论的,可能是 GC 启动了。您可以使用 some runtime options (see section 4.16.3) 来查看更改它们是否会影响此行为。

特别是您可以输出有关 GC 发生的信息以了解是否是问题所在:

-t[file] , -s[file] , -S[file] , --机器可读

这些选项产生运行时系统统计信息,例如执行程序和在垃圾收集器中花费的时间量、分配的内存量、最大大小 堆等。这三个变体给出了不同级别的细节: -t 以与 GHC 的 -Rghc-​​timing 选项相同的格式生成单行输出,-s 在程序结束时生成更详细的摘要,-S 额外生成有关每个垃圾回收的信息。

【讨论】:

    猜你喜欢
    • 2010-11-09
    • 2011-12-18
    • 2015-04-25
    • 1970-01-01
    • 2017-11-13
    • 2011-02-17
    • 1970-01-01
    • 2011-02-20
    相关资源
    最近更新 更多