4

我编写了以下函数,我认为应该以原子方式执行 IO(只要其他人都使用相同的函数MVar)。

atomicIO :: MVar () -> IO a -> IO a
atomicIO mvar io =
  do
    takeMVar mvar
    result <- io
    putMVar mvar ()
    return result

另外,据我了解,Haskell IO 的某些部分是惰性的(例如IORefs),因此无需实际执行本节中的操作。它可以只返回一个“thunk”(这是正确的词吗?),其中列出了需要完成的任务。

这个想法是,关键部分(即单线程部分)应该很快。

但是,假设我正在写信给IORefs,并且我希望 Haskell 立即开始计算结果,所以它可以在需要时执行。但是就像我之前说的,当我们持有锁时,我不想被锁在关键部分MVar

所以我想过这样做:

    result <- io `par` io

或这个

    return result `par` result

或这个

    result `par` return result

但我不确定这是否有效。其中一个是正确的方法,还是有另一种方法?(我对后两者的担忧是IO ()行动,因为我认为并行评估()实际上并没有做任何工作)。

4

2 回答 2

4

你在哪里

writeIORef myRef newValue

将其替换为

newValue `par` writeIORef myRef newValue

这将引发一个线程newValue在后台进行评估......

...但需要注意的是,它只会将其评估为 WHNF(基本上,只会评估数据结构的第一级)。所以 anInt将被完全评估,但 aString不会。一个Maybe a值将被完全评估为Nothing或部分评估为Just _

因此,如果您使用的是更复杂的数据结构,则需要使用forcedeepseq 包中的 from Control.DeepSeq,这将完全评估值。

force newValue `par` writeIORef myRef newValue

如果你想用modifyIORef,我觉得不能modifyIORef直接复用,但是你当然可以定义一个类似的函数无论如何定义modifyIORefreadIORefwriteIORef

modifyIORefInParallel :: NFData a => IORef a -> (a -> a) -> IO ()
modifyIORefInParallel ref f
   = do old <- readIORef ref
        let new = f old
        force new `par` writeIORef ref new

(请注意,如果最后一行是force (f old) `par` writeIORef ref (f old)行不通的:并行强制的值不会是存储在 ref 中的值。)

NFData a限制来自使用force。)

于 2012-04-16T08:25:32.890 回答
1

获得快速关键部分的唯一方法是将自己限制在快速 IO 操作上。我看不出试图在内部强制进行严格的评估atomicIO会如何加快速度。此外,请注意,atomicIO它本身可能没有被严格评估,在这种情况下,内部的严格评估atomicIO没有任何效果。

在任何情况下,您都可以使用seq而不是par进行严格评估,因为您不会尝试触发并行计算。

于 2012-04-16T08:13:49.563 回答