많은 실제 프로그램에서이 목적을 위해 병렬 전략을 사용할 수 있습니다. 불필요한 계산을 취소하는 명시적인 메커니즘이 없지만 가비지 수집기가 실행될 때 암시 적으로 발생하기 때문입니다. 구체적인 예로 다음 프로그램을 고려하십시오.
import Control.Concurrent
import Control.Parallel.Strategies
import Data.Int
import System.Mem
lcgs :: Int32 -> [Int32]
lcgs = iterate lcg
where lcg x = 1664525 * x + 1013904223
hasWaldo :: Int32 -> Bool
hasWaldo x = waldo `elem` take 40000000 (lcgs x)
waldo :: Int32
waldo = 0
main :: IO ()
main = do
print $ or (map hasWaldo [1..100] `using` parList rseq)
이것은 병렬 목록 전략을 사용하여 waldo = 0
각각 4 천만 개의 100 개의 PRNG 스트림 출력에서 검색 할 수 없습니다. 컴파일하고 실행하십시오.
ghc -threaded -O2 ParallelAny.hs
./ParallelAny +RTS -s -N4
그리고 약 16 초 동안 4 개의 코어를 뚫고 결국 인쇄 False
합니다. 통계에서 100 개의 스파크가 모두 "변환"되어 완료 될 때까지 실행됩니다.
SPARKS: 100(100 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
이제 waldo
조기에 찾을 수있는 값으로 변경하십시오 .
waldo = 531186389 -- lcgs 5 !! 50000
main
스레드를 10 초 동안 유지하도록 수정 하십시오.
main :: IO ()
main = do
print $ or (map hasWaldo [1..100] `using` parList rseq)
threadDelay 10000000
True
거의 즉시 인쇄 되지만 4 코어는 100 % CPU에서 (최소한 잠시 동안) 페깅 된 상태로 유지되므로 불필요한 계산이 계속 실행되고 단락되지 않았 음을 알 수 있습니다.
그러나 대답을 얻은 후 가비지 수집을 강제 실행하면 상황이 변경됩니다.
main :: IO ()
main = do
print $ or (map hasWaldo [1..100] `using` parList rseq)
performGC
threadDelay 10000000
이제 인쇄 직후 CPU가 유휴 상태로 떨어지고 True
통계에 따르면 대부분의 계산이 실행 전에 가비지 수집되었음을 알 수 있습니다.
SPARKS: 100(9 converted, 0 overflowed, 0 dud, 91 GC'd, 0 fizzled)
실제 프로그램에서는 performGC
GC가 당연히 정기적으로 수행 되므로 명시적인 것이 필요하지 않습니다. 답을 찾은 후에도 일부 불필요한 계산이 계속 실행되지만 많은 실제 시나리오에서 불필요한 계산의 비율은 특히 중요하지 않습니다.
특히, 목록이 크고 목록 요소에 대한 개별 테스트가 빠르면 병렬 전략은 실제 성능이 뛰어나고 거래에 쉽게 적용 할 수 있습니다.