2012-05-04 5 views
4

wai/warp을 사용하여 State 모나드에 상태를 저장하는 웹 서버를 작성하고 싶습니다. 이 같은 것 :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 패키지에는 잔인한 웹 서버가 필요합니다. Calling Haskell from Node.JS을 참조하십시오. Wai/Warp와 Aeson을 사용하여 간단한 서버를 작성 했으므로 어떤 제안도 없었습니다. 그러나 WAI는 동시 구현을 지원하도록 설계되었으므로 상황이 복잡해졌습니다.

답변

3

상태와의 상호 작용이 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)) 

, 당신은 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

첫 번째 문장은'우선 해석 오류는 혼합 할 수 없습니다. ' [infixr 9]와 'liftM'[infixl 9] 같은 중절 식에서. 두 번째 것은'StateT'와'runStateT'의 모호한 사용을보고합니다; 'import Control.Monad.State'가 주석 처리 된 후에'Not in scope : 유형 생성자 또는 클래스 'ResourceT''; 'Control.Monad.Trans.Resource'를'import '한 후'예상 한 타입과 일치하지 못했습니다'ResourceT IO t0'' – Inaimathi

5

모나드가 State 인 경우 설계 상 thread로부터 안전합니다. 가능한 공유 상태에 대한 동시 IO 조치가 없습니다. 스레드가 안전하지 않거나 컴파일되지 않습니다. 당신은, 당신은 사용해야합니다 및 MVar 또는 TVarSTM monad에서 (또는 다른 트랜잭션 장벽) (글로벌 카운터를 업데이트하는 별도의 forkIO 스레드 예) 설계의 일부로서 공유 상태에 진정으로 병렬 액세스 할 수있는 경우

원 자성을 보장합니다.

+0

가능한 경우 공유 상태에 대한 진정한 병렬 액세스를 피하고 싶습니다. 요청을 순차적으로 제공하고 싶습니다. – nponeccop