6

この疑似コード ブロックでは:

atomically $ do
  if valueInLocalStorage key
      then readValueFromLocalStorage key
      else do
        value <- unsafeIOToSTM $ fetchValueFromDatabase key
        writeValueToLocalStorage key value

安全に使用できunsafeIOToSTMますか? ドキュメントは言う:

  • STM 実装はトランザクションを複数回実行することが多いため、IO に副作用がある場合は、これに備える必要があります。

    基本的に、トランザクションが失敗した場合、他のスレッドが原因でwroteValueToLocalStorageあり、トランザクションが再試行されると、データベースから再度フェッチする代わりに、保存された値が返されます。

  • STM 実装は、無効であることがわかっているトランザクションを中止し、再起動する必要があります。これは unsafeIOToSTM の途中で発生する可能性があるため、解放が必要なリソースを取得しないようにしてください (トランザクションを中止する場合、例外ハンドラーは無視されます)。これには、たとえばハンドルを使用した IO の実行が含まれます。これを間違えると、ランダムなデッドロックが発生する可能性があります。

    これが一番気になります。論理的にfetchValueFromDatabaseは、新しい接続が開かれない場合 (つまり、既存の接続が使用されている場合) は、すべて問題ないはずです。私が見逃している他の落とし穴はありますか?

  • トランザクションは、IO の実行時にメモリの一貫性のないビューを認識した可能性があります。プログラム全体で真であると期待される不変条件は、トランザクションの実装方法により、トランザクション内では真ではない場合があります。通常、これはプログラマーには表示されませんが、unsafeIOToSTM を使用すると公開される可能性があります。

    key単一の値であり、破る不変条件はありません。

4

1 に答える 1

3

STM トランザクションから I/O を実行するのはよくない考えだと思います。

おそらく、2 つのスレッドが同時に DB ルックアップを実行するのを回避する必要があります。私がすることはこれです:

  • アイテムが既にキャッシュにあるかどうかを確認します。もしそうなら、私たちは終わりです。

  • そうでない場合は、「I'm fetching this」フラグでマークし、STM トランザクションをコミットし、DB から取得し、2 つ目の STM トランザクションを実行してキャッシュに挿入します (フラグを削除します)。

  • アイテムにすでにフラグが立てられている場合はretry、トランザクション。これにより、最初のスレッドが DB から値を挿入するまで、呼び出し元のスレッドがブロックされます。

于 2015-12-07T14:10:06.053 に答える