2012-04-16 4 views
4

저는 원자 단위로 수행해야한다고 생각하는 다음 함수를 작성했습니다 (다른 모든 사람들이 동일한 MVar을 사용하는 한).하스켈 : Atomic IO wrapper/laziness?

atomicIO :: MVar() -> IO a -> IO a 
atomicIO mvar io = 
    do 
    takeMVar mvar 
    result <- io 
    putMVar mvar() 
    return result 
또한

, 내가 이해, 하스켈 IO의 일부 게으른 (예를 들면 .. IORef들)이다에서, 그래서 실제로이 섹션의 작업을 수행 할 필요가 없다. 수행해야 할 작업을 나열하는 '썽크'(올바른 단어입니까?)를 반환 할 수 있습니다.

중요한 섹션 (즉, 단일 스레드 부품)은 매우 빠릅니다.

그러나 내가 IORef에 편지를 쓰고 있으며, 결과를 즉시 계산하기를 원하기 때문에 필요할 때 준비가되었습니다. 하지만 전에 말했듯이, MVar 자물쇠를 잡고있을 때 중요한 부분에 갇히고 싶지 않습니다.

그래서 나는이 일에 대해 생각했습니다

result <- io `par` io 

또는이

return result `par` result 

또는이

result `par` return result 

그러나 나는이 일을하지 있는지 확실하지 않습니다. 이들 중 하나가 올바른 접근 방식입니까 아니면 다른 방식입니까? (후자의 두 가지에 대한 나의 관심은 IO() 액션이다. 평행하게 ()을 평가하는 것은 실제로 어떤 일도하지 않는다).

답변

4

...

... 그 WHNF로만 평가할 것입니다 (기본적으로 데이터 구조의 첫 번째 레벨 만 평가됩니다). 따라서 Int은 완전히 평가되지만 String은 그렇지 않습니다. Maybe a 값은 전체적으로 Nothing으로 평가되거나 부분적으로는 Just _으로 평가됩니다.

더 복잡한 데이터 구조를 사용하는 경우 deepseq 패키지의 Control.DeepSeq에서 force을 사용해야합니다. 그러면 값을 완전히 평가하게됩니다.당신이 modifyIORef를 사용하려면

force newValue `par` writeIORef myRef newValue 

, 난 당신이 직접 modifyIORef를 다시 사용할 수 있다고 생각하지 않습니다,하지만 당신은 확실히 유사한 기능 (modifyIORef is defined in terms of readIORef and writeIORef anyway) 정의 할 수 있습니다 :

modifyIORefInParallel :: NFData a => IORef a -> (a -> a) -> IO() 
modifyIORefInParallel ref f 
    = do old <- readIORef ref 
     let new = f old 
     force new `par` writeIORef ref new 

은 (주 그 경우 마지막 줄은 force (f old) `par` writeIORef ref (f old) 이었지만 작동하지 않습니다. 병렬로 강제 실행 된 값은 참조에 저장된 값이 아닙니다.

(NFData a 제한은 force을 사용하는 것입니다.)

+0

dave4420 : 'modifyIORef'와 비슷한 방법이 있습니까, 아니면 별도의'readIORef'와'writeIORef'가 필요합니까? – Clinton

+0

(어쨌든 비록 주위에 자물쇠가 있어도별로 중요하지 않다고 생각합니다.) – Clinton

+0

@Clinton 내 편집을 참조하십시오. – dave4420

1

빠른 임계 구역을 얻는 유일한 방법은 빠른 IO 작업으로 제한하는 것입니다. atomicIO 안에 엄격한 평가를 강요하면 어떻게 속도가 올라가는지 알 수 없습니다. 또한 atomicIO 자체는 엄격하게 평가되지 않을 수도 있으며,이 경우 atomicIO 내부의 엄격한 평가는 아무런 영향을 미치지 않습니다.

어떤 경우 든 평행 계산을 촉발 시키려하지 않으므로 엄격한 평가를 위해 par 대신 seq을 사용할 수 있습니다. 주의해야 할 점으로는

writeIORef myRef newValue 

newValue `par` writeIORef myRef newValue 
백그라운드에서 newValue을 평가하는 스레드를 촉발합니다

와 그 교체가