Haskell超时发散计算

6

我正在尝试在Haskell中编写一个安全的定时评估函数。 代码如下:

import System.Timeout

compute, compute' :: Int -> Int
compute  i = sum [1..300000 + i]
compute' i = last $ repeat i

timedComp :: Int -> a -> IO (Maybe a)
timedComp timeLeft toCompute =
        timeout timeLeft go
    where
        go = toCompute `seq` return toCompute

main = do
    res <- timedComp 10000 (compute 0)
    print res

    res' <- timedComp 10000 (compute' 0)
    print res'

我知道我的值只会被求值到弱头正常形式。

当我运行主函数时,输出只有一个Nothing,然后程序就卡住了。我尝试将程序编译并以多线程方式运行,但没有帮助。在GHC 7.6.3和7.8.3上都尝试过。有什么建议吗?


4
我担心 compute' i = last $ repeat i 经过优化后可能不需要任何分配空间。如果是这种情况,GHC 调度程序就无法切换到其他的 Haskell 线程。这是 GHC 的一个已知“限制”(好吧,是个 bug)。希望有一天 GHC 至少会在这种情况下发出警告。 - chi
3
为了避免@chi提到的问题,如果这确实是你遇到的问题,在构建时请使用-fno-omit-yields - Reid Barton
@chi: 你能将那个作为答案吗?或许结合Reid Barton的建议一起呈现? - Tikhon Jelvis
谢谢大家,现在我更好地理解了发生了什么! - Tomáš Jakl
1个回答

3
GHC实现的Haskell线程存在限制:上下文切换仅在分配期间发生。因此,完全不进行分配的紧密循环可能会阻止调度程序运行并切换到其他线程。
以下是这种情况的一个例子:compute' i = last $ repeat i 看起来好像正在分配列表单元,但不幸的是,GHC能够将其优化为微不足道的无限循环,删除所有分配--GHC Core大致如下:f x = f x。这触发了调度程序的缺陷。
Reid Barton建议使用选项-fno-omit-yields来解决这个问题。这将导致GHC不要那么多优化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接