私は並行性を理解しようとしてきました。そして、1つの大きなIORef
ロック、または多くTVar
のロックのどちらが優れているかを理解しようとしています。私は以下のガイドラインに到達しました。これらが大まかに正しいかどうか、または私が要点を見逃したかどうかについて、コメントをいただければ幸いです。
同時データ構造がマップm
であり、のようにアクセスされると仮定しましょうm[i]
。f_easy
また、2つの関数があるとしましょうf_hard
。はf_easy
速く、f_hard
時間がかかります。f_easy/f_hard
の引数はの要素であると想定しますm
。
(1)トランザクションがおおよそこのように見える場合は、 withをm[f_easy(...)] = f_hard(...)
使用します。怠惰は、サンクで更新されるため、短時間だけロックされるようにします。インデックスを計算すると、構造が効果的にロックされます(何かが更新されるためですが、まだ何がわかりません)が、その要素が何であるかがわかると、構造全体のサンクはその特定の要素のサンクにのみ移動します、そしてその特定の要素のみが「ロック」されます。IORef
atomicModifyIORef
m
(2)トランザクションがおおよそこのようm[f_hard(...)] = f_easy(...)
になり、競合があまり発生しない場合は、をたくさん使用しますTVar
。この場合にを使用するIORef
と、2つのインデックスを同時に計算できないため、アプリが効果的にシングルスレッドになります(構造全体に未解決のサンクが存在するため)。TVar
■2つのインデックスを同時に処理できますが、2つの同時トランザクションが両方とも同じ要素にアクセスし、そのうちの1つが書き込みである場合、1つのトランザクションを破棄する必要があり、時間が無駄になります(他の場所で使用)。これが頻繁に発生する場合は、(ブラックホールを介して)から来るロックを使用した方がよい場合がありますが、IORef
あまり発生しない場合は、TVar
sを使用した方が並列処理が向上します。
基本的に(2)の場合、IORef
100%の効率(無駄な作業なし)が得られる可能性がありますが、1.1スレッドのみを使用しTVar
ますが、競合の数が少ない場合は、80%の効率が得られる可能性がありますが、10スレッドを使用するため、終了します。無駄な作業でも7倍速くなります。