13

私はHaskellで並行性を使用して、2つの値の1つだけが必要な特定の最適化を試みています。状況によっては、どちらか一方の方がもう一方よりもはるかに高速に作成できる場合があります。

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)

コンパイル済み:

ghc --make -threaded Test

ただし、プライムの取得にはmakeIntスレッドが開始するのに十分な時間がかかるはずですが、Leftの場合にのみ到達します(2を返すのにそれほど時間はかからないはずです)。それはなぜですか、そしてどうすればこれを修正できますか?

4

2 に答える 2

20

ここでの問題は怠惰です。はmakeString、サンクを挿入して計算show (primes !! 10000)し、その後メインスレッドによって評価されます。サンクの挿入は非常に速いので、この場合はたまたまレースに勝ちます。

スレッド内で評価を強制的に実行するには、次のように変更できreturnますevaluate

makeString out = do s <- evaluate $ show (primes !! 10000)
                    putMVar out $ Left s

これによりmakeInt、ほとんどの場合、レースに勝つことができます(ただし、保証はされていません)。

于 2012-04-20T13:56:02.493 に答える
10

はい、スレッドは実際には非決定的です(GHCで)。

特定のコードが、t1が常に勝つように構造化および最適化されていることが起こります。保証はありません。

別の結果を生成するためにそれをマッサージしようとする場合は、最適化をオンにするか(-O2)、および/または複数のコアを使用してみてください(+RTS -N)。

たとえば、私のマシンでは、2つ続けて実行します。

$ 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

hammarが指摘しているように、コードを構造化して、スレッドでより多くの作業を強制的に実行することもできます(または、厳密なmvarの使用に切り替えることもできます)。

于 2012-04-20T13:50:49.407 に答える