限制Haskell计算的运行时间

我在Haskell中编写游戏AI,我想在指定的时间内搜索游戏状态树(例如,我希望AI始终花3秒钟来决定采取什么行动)

在像Haskell这样的纯语言中,我该如何实现这一点?我预计我需要深入研究线程等内容,但如果可以的话,我希望尽量减少这方面的使用。


回答:

一个想法:结合timeout(由@MathematicalOrchid建议)以及来自SafeSemaphore的可变变量,每次你的进程计算出部分结果时存储中间值:

import Control.Monadimport Control.Concurrent.MSampleVarimport System.Timeoutfac :: Integer -> Integerfac 0 = 1fac n = n * fac (n - 1)tmo :: Int -> ((a -> IO ()) -> IO ()) -> IO (Maybe a)tmo ms f = do    mvar <- newSV Nothing    timeout ms (f (writeSV mvar . (Just $!)))    readSV mvarlongComp :: (Integer -> IO ()) -> IO ()longComp save = let loop n = save (fac n) >> loop (n + 1)                in loop 0main :: IO ()main = tmo 10000 longComp >>= print

传递给tmo的函数将其第一个参数作为一个IO动作,用于保存中间结果。如果超时,最后保存的结果将被返回。结果被转换为WHNF,因此实际计算发生在保存结果的线程中,而不是在从tmo返回时处理它的线程中。

在这种变体中,传递给tmo的函数必须保存其输出,而不能返回它。但很容易修改它的签名,使其为(a -> IO ()) -> IO a

如果你想保持更纯净的代码,我建议你创建一个自己的单子(monad),来封装这个想法而不让IO泄露出来。


更新:请注意:

无法保证异常会立即被传递,尽管运行时会努力确保不会发生任意延迟。在GHC中,只有当线程到达安全点时才会引发异常,安全点是指发生内存分配的地方。有些循环在循环内部不执行任何内存分配,因此无法被throwTo中断。

(来自throwTo的文档)。在上面的例子中,fac不分配任何内存,因此对于大数它不会立即被中断。

更新:我基于这些想法创建了一个小型库,该库定义了可以返回部分结果的单子,在返回最终结果之前或在超时时终止。请参见https://github.com/ppetr/timeout-with-results

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注