Cub*_*bic 13 concurrency haskell
我正在尝试在Haskell中使用并发进行特定的优化,其中只需要两个值中的一个,并且根据情况,任何一个可能比另一个更快.
我以为我可以用forkIO运行2个线程,然后等到一个值放在一个MVar中.这是一个我为此编写的简单测试:
import Control.Concurrent
main = do out <- newEmptyMVar
t1 <- forkIO (makeString out)
t2 <- forkIO (makeInt out)
v <- takeMVar out
killThread t1
killThread t2
case v of
Left s -> putStrLn s
Right i -> putStrLn $ show i
makeString out = do s <- return ( show (primes !! 10000))
putMVar out $ Left s
makeInt out = do i <- return 2
putMVar out $ Right i
primes = sieve [2..]
where sieve (x:xs) = x : (sieve $ filter ((/=0).(flip mod x)) xs)
Run Code Online (Sandbox Code Playgroud)
编译:
ghc --make -threaded Test
Run Code Online (Sandbox Code Playgroud)
但是,只有Left的情况才会到达,虽然获取素数应该花费足够长的时间来启动makeInt线程(并且返回2确实不应该花费那么多时间).为什么会这样,我该如何解决这个问题?
ham*_*mar 20
这里的问题是懒惰.在makeString刚刚插入一个thunk来计算show (primes !! 10000),然后把它由主线程事后评估.插入thunk的速度相当快,所以在这种情况下碰巧赢得比赛.
要强制在线程内进行评估,您可以更改return为evaluate:
makeString out = do s <- evaluate $ show (primes !! 10000)
putMVar out $ Left s
Run Code Online (Sandbox Code Playgroud)
makeInt在大多数情况下,这应该会赢得比赛(尽管不能保证).
Don*_*art 10
是的,线程确实是非确定性的(在GHC中).
只是发生了你的特定代码的结构和优化,以便t1总是获胜.没有保证.
如果您想尝试按摩它以产生不同的结果,请尝试启用优化(-O2)和/或使用多个核心(+RTS -N).
例如在我的机器上,连续两次运行:
$ ghc -O2 -threaded --make A.hs -rtsopts -fforce-recomp
[1 of 1] Compiling Main ( A.hs, A.o )
Linking A.exe ...
$ ./A +RTS -N2
2
$ ./A +RTS -N2
104743
Run Code Online (Sandbox Code Playgroud)
正如hammar指出的那样,您还可以构建代码以强制在线程中进行更多工作(或切换到使用严格的mvars).
| 归档时间: |
|
| 查看次数: |
1473 次 |
| 最近记录: |