2016-09-25 4 views
1

次は(のように:それは毎秒Surely tomorrowを言って続けて)動作するようです。これは、last [0..]が実際にMVarを充填する前にWHFNに強制されていることを確認するためにevaluateを使用しています

import Control.Concurrent 
import Control.Concurrent.MVar 

import Control.Exception (evaluate) 

main :: IO() 
main = do 
    godot <- newEmptyMVar 
    forkIO $ do 
     g <- evaluate $ last [0..] 
     putMVar godot g 
    let loop = do 
     threadDelay $ 10^6 
     g <- tryTakeMVar godot 
     case g of 
      Just g -> return() 
      Nothing -> putStrLn "Surely tomorrow." >> loop 
    loop 

- 私は

にフォークスレッドを変更した場合
forkIO $ do 
     let g = last [0..] 
     putMVar godot g 

プログラムを終了します。

ただし、evaluateseqを使用します。決定論的な並列性の文脈では、seqは評価順序を実際に保証するには不十分であることが常に強調されています。この問題は、モナドのコンテキストで発生していない、または私はより良いtryTakeMVarが途中で成功したように、コンパイラは、評価の順序を変更することはできません確実にするために

forkIO $ do 
     let g = last [0..] 
     g `pseq` putMVar godot g 

を使用する必要がありますか?

答えて

0

pseqのポイントは、親スレッドがparで計算を開始した後、直ちにスポーク計算の結果を評価しようとするのではなく、最初に自身のジョブを実行することです。例については、the documentationを参照してください。並行処理で明示的に作業する場合は、pseqは不要です。

1

もし完全に間違っていないなら、IntのWHNFはあなたが正確な数を知っているので、last [0..]からWHNFを評価するのに無限の時間がかかるでしょう。 last [0..]は(我々が知っているようには永遠にかかります)WHNFに評価される前にputMVarevaluateの呼び出しによって返さRealWorld -token(s)が必要になりますので

putMVarは、実行を開始しません。 (以上、単純にそれを置くために:。evaluate作品をそれだけでWHNFにその引数を評価した後に終了します。)

seq#はそれだ(だけWHNFに aを評価した後 (# a, s #)を返すために保証GHC-プリム機能です
evaluate :: a -> IO a 
evaluate a = IO $ \s -> seq# a s 
--      this ^

putMVar (MVar mvar#) x = IO $ \ s# -> 
--   which is used here ^^ 
    case putMVar# mvar# x s# of 
--   is needed here ^^ 
     s2# -> (# s2#,() #) 

その目的)。すなわち、aがWHNFと評価された後にのみ、putMVarへの呼び出しでsを使用できます。これらのトークンは純粋に想像力豊かですが(「RealWorldは深く魔法です...」)、コンパイラによって尊重され、IOモナド全体がその上に構築されます。

だから、この場合はevaluateで十分です。 evaluateseqより大きく、IO-モナド配列決定とseq#シークエンシングを組み合わせてその効果を生み出します。それは最終的に最終的にseq#とモナドトークンパッシングに依存evaluatelazy、に依存しているため、


は実際には、pseqバージョンは、私には少し怪しい見えます。そして私はseq#をもう少し信じています。

関連する問題