2012-04-18 46 views
3

據我瞭解,修改IORef s爲非常快,所有它們涉及正在更新一個thunk指針。當然,讀者(即希望在他們的網頁上看到價值的人)需要花時間來評估這些thunk(如果作者不讀回結果,這可能會增加)。哈斯克爾:嘗試在平行`atomicModifyIORef`實施

我在想,開始實際上並行地評估IORef上的修改thunk會很好,因爲在很多情況下,它們可能都必須在某個點上進行評估(顯然,這將打破無限的數據結構)。

所以我寫了下面的功能,具有相似的簽名atomicModifyIORef

atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b 
atomicModifyIORefPar ioref f = 
    let 
    g olddata = 
     let (newdata, result) = f olddata in (newdata, (result, newdata)) 
    in do 
    (result, newdata) <- atomicModifyIORef ioref g 
    force newdata `par` return result 

這似乎是工作(test code here)。有什麼我在這裏做錯了嗎?還是有更好的方法來做到這一點?


編輯:第二次嘗試

通過Carl's answer below啓發。我們實際上將force newdata存儲在IORef中。這是一樣的newdata無論如何,但表明我們希望保持force newdata供以後運行,所以也沒有垃圾收集的火花。

atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b 
atomicModifyIORefPar ioref f = 
    let 
    g olddata = 
     let 
     (newdata, result) = f olddata 
     newdata_forced = force newdata 
     in 
     (newdata_forced, (result, newdata_forced)) 
    in do 
    (result, newdata_forced) <- atomicModifyIORef ioref g 
    newdata_forced `par` return result 
+0

我看不錯,但不知何故,我希望'取代'IORef' MVar'原子事務時。 – ephemient 2012-04-18 06:32:26

+0

難道你不能定義IORef嚴格嗎?像IORef!Bla – 2012-04-18 14:22:48

+0

@VagifVerdi:這會不會減慢編寫者,同時鎖定'IORef'直到修改函數被計算出來? – Clinton 2012-04-18 14:48:30

回答

4

根據GHC的版本,這可能會也可能不會。火花池與GC的相互作用在整個歷史中都是可變的。在一些版本中,一個事實,即表達force newdata沒有後atomicModifyIORefPar收益率的範圍的任何提及意味着它很可能是收集之前par產生的火花不斷轉換,這意味着火花也將被收集垃圾。

GHC的其他版本對待火花池在GC分析根源,但有問題了。我不記得目前的狀態是什麼,但我懷疑這是火花池不算GC的根源。它引發的問題(當返回的表達式不引用並行計算的表達式時,並行性喪失)不如將GC作爲GC根(保留不需要的內存)所產生的問題那麼糟糕。


編輯 - 在回答

這種新的實現第二次嘗試看起來正確,因爲你給的理由。並行評估的表達也可從GC根中獲得。

+0

您可以在上面編輯的問題中對我提出的解決方案發表評論嗎? – Clinton 2012-04-19 01:26:53

+1

@Clinton我更新了我的答案。 – Carl 2012-04-19 02:12:30

+0

感謝您的幫助! – Clinton 2012-04-19 02:20:49