我想写一个web服务器,用wai/warp在State monad中存储它的状态。如下所示:
{-# 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当然,注释行不起作用。其目的是在monad状态中存储一个计数器,并在每次请求时显示其递增的值。
另外,如何获得线程安全性?warp是按顺序还是并行运行我的中间件?
状态有哪些可用选项-除了IORef之外,我还可以在此场景中使用其他选项吗?
我知道State提供了安全性,但似乎wai不允许State。
我只需要一个非常简单的单线程RPC,我可以从其他地方调用它。Haxr包需要单独的web服务器,这是一种过度的杀伤力。查看Calling Haskell from Node.JS -它没有任何建议,所以我使用Wai/Warp和伊森编写了一个简单的服务器。但似乎WAI是为支持并发实现而设计的,所以它使事情变得复杂。
发布于 2012-05-04 23:47:45
如果您与状态的交互可以通过一个对atomicModifyIORef的调用来表示,那么您就可以使用它,并且不需要显式地序列化对状态的访问。
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))如果您的交互比较复杂,并且需要强制执行请求的完全序列化,则可以将MVar与StateT结合使用。
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发布于 2012-05-04 21:37:53
如果它在State monad中,那么它在设计上是线程安全的。不可能对共享状态执行并发IO操作。它要么是threadsafe,要么不能编译。
如果你有真正的并行访问共享状态作为设计的一部分(例如,独立的forkIO线程更新全局计数器),那么你将需要在STM monad (或其他事务屏障)中使用和MVar或TVar来确保原子性。
https://stackoverflow.com/questions/10449819
复制相似问题