私は並行性を理解しようとしてきました。そして、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(...)使用します。怠惰は、サンクで更新されるため、短時間だけロックされるようにします。インデックスを計算すると、構造が効果的にロックされます(何かが更新されるためですが、まだ何がわかりません)が、その要素が何であるかがわかると、構造全体のサンクはその特定の要素のサンクにのみ移動します、そしてその特定の要素のみが「ロック」されます。IORefatomicModifyIORefm
(2)トランザクションがおおよそこのようm[f_hard(...)] = f_easy(...)になり、競合があまり発生しない場合は、をたくさん使用しますTVar。この場合にを使用するIORefと、2つのインデックスを同時に計算できないため、アプリが効果的にシングルスレッドになります(構造全体に未解決のサンクが存在するため)。TVar■2つのインデックスを同時に処理できますが、2つの同時トランザクションが両方とも同じ要素にアクセスし、そのうちの1つが書き込みである場合、1つのトランザクションを破棄する必要があり、時間が無駄になります(他の場所で使用)。これが頻繁に発生する場合は、(ブラックホールを介して)から来るロックを使用した方がよい場合がありますが、IORefあまり発生しない場合は、TVarsを使用した方が並列処理が向上します。
基本的に(2)の場合、IORef100%の効率(無駄な作業なし)が得られる可能性がありますが、1.1スレッドのみを使用しTVarますが、競合の数が少ない場合は、80%の効率が得られる可能性がありますが、10スレッドを使用するため、終了します。無駄な作業でも7倍速くなります。