web-dev-qa-db-ja.com

GHCのサンクはどのくらいアトミックですか?

GHCは、複数のスレッド(明示的なスレッド、またはスパークを評価する内部スレッド)によってアクセスされるサンクをどのように処理しますか?複数のスレッドが同じサンクを評価し、作業を複製する可能性はありますか?または、サンクが同期されている場合、パフォーマンスが低下しないようにするにはどうすればよいですか?

48
Petr Pudlák

ブログ投稿 @Lambdageekリンクから、 GHC解説 および GHCユーザーガイド 私は以下をつなぎ合わせます:

GHCはサンクの再評価を防止しようとしますが、スレッド間の真のロックにはコストがかかり、サンクは通常純粋で再評価しても無害であるため、通常はsmallとにかく作業を複製する可能性。

作業を回避するために使用する方法は、サンクをブラックホールに置き換えることです。これは、他のスレッド(または場合によってはスレッド自体)に通知する特別なマーカーです。 <<loop>>検出が発生します)サンクが評価されていること。

これを考えると、少なくとも3つのオプションがあります。

  • デフォルトでは、「レイジーブラックホール」を使用します。これは、スレッドが一時停止する前にのみ実行されます。次に、スタックを「ウォーク」し、新しいサンクの「真の」ブラックホールを作成します。ロックを使用して、各サンクが1つのスレッドのみをブラックホール化するようにし、別のスレッドがすでにサンクをブラックホール化したことを検出すると、独自の評価を中止します。これは、評価時間が2つの一時停止の間に完全に収まるほど短いサンクを考慮する必要がないため、より安価です。

  • とともに - -feager-blackholing-flag 、代わりに、サンクが評価を開始するとすぐにブラックホールが作成されます。多くの並列処理を行う場合は、ユーザーガイドでこれを推奨しています。ただし、すべてのサンクをロックするのはコストがかかりすぎるため、これらのブラックホールは安価な「熱心な」ブラックホールであり、他のスレッドと同期されません(ただし、競合状態がない場合でも他のスレッドはそれらを見ることができます)。スレッドが一時停止した場合にのみ、これらは「真の」ブラックホールに変わります。

  • ブログ投稿が特に取り上げた3番目のケースは、unsafePerformIOのような特別な関数に使用され、有害を評価します。何度もサンク。この場合、スレッドは実際のロックを備えた「真の」ブラックホールを使用しますが、実際の評価の前に人工的なスレッドの一時停止を挿入することにより、すぐにそれを作成します。

43
Ørjan Johansen

コメントにリンクされている記事を要約すると、GHCのサンクは複数のスレッド間で厳密にアトミックではありません。競合状態では、複数のスレッドが同じサンクを評価し、作業を複製する可能性があります。しかし、これは実際には大したことではありません。理由は次のとおりです。

  1. 保証された純度は、プログラムのセマンティクスの観点から、サンクが2回評価されるかどうかが問題にならないことを意味します。 unsafePerformIOはそれが問題になる可能性がある場合ですが、unsafePerformIOは同じIOアクションを再実行しないように注意していることがわかりました。
  2. すべての値がサンクであるため、ほとんどのサンクは非常に小さいことがわかります。したがって、プログラムの速度の観点から、作業を複製して強制することは大したことではありません。たとえば、last [1,2..10000000]は計算全体が高価であるため、複製するのに費用がかかると想像するかもしれません。しかしもちろん、実際には最も外側のサンクは、次のような別のサンクに解決されます。

    case [1,2..10000000] of 
      [x] -> x
      (_:xs) -> last xs
      [] -> error "empty list"
    

    そして、2つのスレッドがlastの呼び出しをcaseの使用に変える作業を複製する場合、それは物事の壮大な計画ではかなり安価です。

22
amalloy

はい、同じサンクを複数のスレッドで評価できる場合があります。 GHCランタイムは、重複する作業の可能性を最小限に抑えようとするため、実際にはまれです。低レベルの詳細、主に「ロックフリーサンク評価」セクションについては、 "共有メモリマルチプロセッサ上のHaskell" ペーパーを参照してください。 (私はすべてのプロのhaskell開発者にこの紙をお勧めします。)

13
Yuras