2012-05-04 4 views
4

wai/warpStateモナドに状態を格納するWebサーバーを作成したいとします。このような何か:Warp/WAIによるスレッドセーフ状態

{-# LANGUAGE OverloadedStrings #-} 
import Network.Wai 
import Network.Wai.Handler.Warp 
import Network.HTTP.Types 
import Control.Monad.State 
import Data.ByteString.Lazy.Char8 

main = run 3000 app 

text x = responseLBS 
     status200 
     [("Content-Type", "text/plain")] 
    x 

app req = return $ text "Hello World" 

app1 req = modify (+1) >>= return . text . pack . show 

-- main1 = runStateT (run 3000 app1) 0 

コメント行はもちろん、動作しません。その目的は、状態モナドにカウンタを格納し、すべての要求に対して増加する値を表示することです。

スレッド安全性を取得するにはどうすればよいですか?ワープはミドルウェアを順番に、または並行して実行しますか?

州にはどのようなオプションがありますか?このシナリオではIORef以外に何かがありますか?

私は州が安全を認めているが、州は許可していないようです。

私は死んで簡単なシングルスレッドRPCが必要です。どこからでも呼び出すことができます。 Haxrパッケージには、余計なWebサーバーが必要です。 Calling Haskell from Node.JSを参照してください。私はWai/WarpとAesonを使ってシンプルなサーバーを書いたので、何も提案はありませんでした。しかし、WAIはコンカレントな実装をサポートするように設計されているため、複雑なものになっているようです。

答えて

3

状態との対話がatomicModifyIORefへの1回の呼び出しで表現できる場合は、それを使用することができ、状態へのアクセスを明示的にシリアル化する必要はありません。

import Data.IORef 

main = do state <- newIORef 42 
      run 3000 (app' state) 

app' :: IORef Int -> Application 
app' ref req 
    = return . text . pack . show `liftM` atomicModifyIORef ref (\st -> (st + 1, st + 1)) 

あなたの相互作用が複雑であり、あなたがリクエストの完全なシリアル化を強制する必要がある場合は、StateTと一緒にMVarを使用することができます。

import Control.Concurrent.MVar 
import Control.Monad.State.Strict 

main = do state <- newMVar 42 
      run 3000 (app' state) 

app' :: MVar Int -> Application 
app' ref request 
    = do state <- takeMVar ref 
     (response, newState) <- runStateT (application request) state 
     putMVar newState --TODO: ensure putMVar happens even if an exception is thrown 
     return response 

application :: Request -> StateT Int (ResourceT IO) Response 
application request = modify (+1) >>= return . text . pack . show 
+0

最初のものは 'Precedence parsing error can not mixed 'と表示されます。 [infixr 9]と 'liftM' [infixl 9]を同じ中置式で使用する。 2つ目は、 'StateT'と' runStateT'のあいまいな使い方を報告します。 'importControl.Monad.State'がコメントされた後、'スコープ内にありません:タイプコンストラクタまたはクラス 'ResourceT''; 'Control.Monad.Trans.Resource'を' import 'した後、 '予想される型に一致できませんでした'と報告します。ResourceT IO t0'' – Inaimathi

5

Stateモナドにある場合は、設計上スレッドセーフです。共有状態への同時IOアクションはありません。スレッドセーフであるか、コンパイルされません。あなたは、あなたが使用する必要がありますし、MVarまたはTVarSTM monad中(またはいくつかの他のトランザクションの障壁)(グローバルカウンタを更新し、別forkIOスレッドすなわち)あなたのデザインの一部として共有状態への真の並列アクセスを持っている場合は

原子性を保証する。

+0

可能であれば、本当に共有状態へのアクセスを避けたいと思います。私は要求を連続して受けたい。 – nponeccop