2012-04-16 40 views
4

我写了下面的函数,我相信应该以原子方式执行IO(只要其他人使用相同的MVar)。Haskell:原子IO包装/懒惰?

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

而且,从我的理解,哈斯克尔IO的某些部分是懒惰(例如.. IORef S),所以无需实际执行本节中的操作。它只能返回一个'thunk'(这是正确的词?),它列出了需要完成的任务。

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

但是,可以说我正在写IORef s,我希望Haskell立即开始计算结果,因此可以在需要时做好准备。但就像我之前说过的,当我们持有MVar锁时,我不想锁定在关键部分。

所以我想过这样做:

result <- io `par` io 

或本

return result `par` result 

或本

result `par` return result 

但我不知道,如果这样做的工作。这是正确的方法之一,还是有另一种方式? (我对后两者的关注是IO()动作,因为我并没有真正做任何工作,我并没有评估())。

回答

4

如果你有

writeIORef myRef newValue 

替换与

newValue `par` writeIORef myRef newValue 

这将引发一场线程,以评估在后台newValue ...

...需要提醒的是它只会将其评估为WHNF(基本上,只有数据结构的第一级才会被评估)。所以Int将被完全评估,但String不会。 A Maybe a的值将被完全评估为Nothing或部分评估为Just _

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

force newValue `par` writeIORef myRef newValue 

如果你想使用modifyIORef,我不认为你可以直接重用modifyIORef,但你肯定可以定义类似的功能(modifyIORef is defined in terms of readIORef and writeIORef anyway)

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)它不会工作:并行强制的值不会是存储在参考中的值。)

NFData a限制来自force。)

+0

dave4420:有没有办法用'modifyIORef'做类似的事情,还是我需要做一个单独的'readIORef'后跟'writeIORef'? – Clinton 2012-04-16 08:59:55

+0

(我猜这无关紧要,尽管无论如何我已经锁定了它) – Clinton 2012-04-16 09:05:59

+0

@Clinton看到我的编辑。 – dave4420 2012-04-16 09:22:12

1

获得快速关键部分的唯一方法是将自己限制为快速IO操作。 我不明白如何试图在atomicIO内强制进行严格评估会给你带来任何加速。此外,请注意atomicIO本身可能不会被严格评估,在这种情况下atomicIO内的严格评估没有任何影响。

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