Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ZIOで触るSTM

8325e1e259e53459bb2d9e0e3ff7262d?s=47 keiSunagawa
September 25, 2020
140

 ZIOで触るSTM

8325e1e259e53459bb2d9e0e3ff7262d?s=128

keiSunagawa

September 25, 2020
Tweet

Transcript

  1. ZIOで触るSTM

  2. 自己紹介 名前: 砂川 恵 所属: 株式会社FOLIO (もうすぐ入社一年)

  3. 注意事項 - ZIOの話をしますがFOLIOではZIOを使っていません - ZIOのversionは1.0.1 - ZIO自体の話はあまりしません, あくまでzio.stm.STMの話に絞る

  4. みなさん並列処理は好きですか? 好きですよね?

  5. でも並列処理って難しいですよね 親の顔より見た入出金の例 - 口座はそれぞれAtomicで更 新する場合はロックを取得す る - トランザクションはcommitか rollbackを行うまでは取得した ロックを解放しない

  6. 口座が二つぐらいなら制御可能だが… 実際は無数の口座を扱う むりぃ。。

  7. その悩みSTMで解決できますよ?

  8. (Software) Transactional Memory - 並列処理を制御するための仕組み/実装 - DBトランザクションのようなトランザクションをメモリ上のデータに対して提 供する - 悲観ロック

    - commit時にデータの変更を検知し、処理時とのデータの相違があれば先 頭から処理をやり直す - Software Transactional Memory(STM)はTransaction Memoryをソフト ウェア上(特定の言語上など)で実装したもの
  9. ZIO 元々はscalaz8のIOモナドとして開発されていたライブラリだが、現在はスタンドアロンなライブラリとしてリリースされている。 IOモナドとは元々Haskellの技術で副作用をコンテキストとして持つ値で、副作用が失敗したときの例外処理などをハンドリ ング/mask/割り込みなどのための様々な関数が定義されている。正しく言うと IO自体はただのデータ型でIOデータ型がモナ ド型クラスを実装している。 ScalaでのIOモナドは並列処理周りの実装やヘルパー関数も定義されており、 HaskellのIOモナ ドよりさらに機能が拡張されている場合が多い。 IO値は遅延性のタスクであり、定義のみでは実行されず

    run関数を発火する ことで実行することができる、さらに IOは再利用可能であるため、 run関数はなんども呼び出すことができる (その度に副作用 タスクが実行される)。IOはモナドを実装しているため合成が可能で、一般的には for syntaxを利用して逐次処理同様に書く ことができる。scalaに置けるIOの代表的な実装としてはcats.effect.IOがあり、IOの類似や派生としてmonix TaskやZIOが 存在する。これらは総称してエフェクトラッパーと呼ばれることがある。 ZIOはIOモナドにさらにDI機能を追加したりエラー型を 任意の型に束縛できるようにしたりとさらにリッチにしたもので型として ZIO[R, E, A]となりRがDIするmoduleの型、Eがエ ラー型、AがIOタスクの戻り値となる。Rの値にはaccessM関数でアクセスすることが可能でこれの戻り値は ZIOとなり、つま りRにアクセスする場合は必ず ZIOコンテキストになる。ZIOはそのほかにもSTMやStreamなど並列処理を行うに当たって 有用なモジュールも提供されており、大体の処理を ZIOのみで完結できるようになっている、反対に cats.effect.IOなどとの相 互変改も提供されており他エフェクトラッパーとの共存や、移行などもやりやすいようになっている。
  10. ZIO 長い、 三行で - 副作用をラップし、再実行可能なタスクとして変数に束縛できる - 並列処理用のモジュールが提供されている - DI機能とかも提供されている

  11. ZIOで提供されているモジュール(一例) - ZIO DI機能付きエフェクトラッパー - Fiber マイクロスレッド - Ref AtomicRefalence

    - Semaphore セマフォ - Chunk Arrayベースのハイパフォーマンス Collection - Queue 非同期で利用可能なQueue - Managed Closableなリソースを扱うためのモジュール (≒ cats.effect.Resource) - STM 悲観ロック トランザクション - Stream stream処理
  12. zio.stm.STM https://gist.github.com/keiSunagawa/13b30afae7e3b017a0ab5bdd75efa30c 口座はTRefとして表現される 口座(トランザクション処理対象の 値)を任意数作成する関数 片方の口座から出金 もう片方の口座へ入金をする トランザクション処理 STM操作を合成してひとつのトラ ンザクションを生成できる

    この戻り値のSTMをさらに合成し て大きなトランザクションにするこ ともできる USTM[A]はSTM[Nothing, A]の type alias
  13. zio.stm.STM https://gist.github.com/keiSunagawa/13b30afae7e3b017a0ab5bdd75efa30c STM#commitを呼び出すことで トランザクションを実行できる コミット後はIOタス クになる (遅延実行) forkはprogram0の返す IOタスクを並列で実行す る

  14. zio.stm.STMに置けるロールバック - コミット時に値の変更を検査し、自分のトラザクション以外から変更されていた場合 ロールバックし、処理をやり直す - 当然ロールバックできるのはメモリ上のデータ(TRefインスタンス)だけ - つまりSTMトランザクション内では副作用を実行できない

  15. zio.stm.STMに置けるコミット - メモリ上のデータ(TRefインスタンス)を更新する - コミット時のTRefに対する値の検査と更新処理はsynchronized blockで実行され る - 更新すべき値が多いほどこのblock時間が長くなる

  16. まとめ - STMは並列処理上に悲観ロック トランザクションを提供するもの - ユーザはロックの概念を意識せず、任意数のobjectを扱える - ZIOではSTMの実装が提供されている - DBトランザクションのようにコミット/ロールバックの概念が存在する

    - ロールバックが発生した場合はトランザクションの先頭から処理をやりなおす - コミット処理はsynchronized blockで実行される
  17. 時間があれば、実装の話をしたい - TRefはVersion付けされた値を持つ https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZTRef.scala#L175-L178 - Versionedはただの値のwrapper class 新しいversion = 新しいインスタンス

    https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZSTM.scala#L1500
  18. 時間があれば、実装の話をしたい - トランザクションではjournalと言うMapを引き回し、値を更新(set関数呼び出し)をし た場合はVersionedの値ではなく、更新予定の値をjournalに記録していく(そのとき 現在のVersion付きの値も一緒に格納する) https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZTRef.scala#L214-L219 https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZTRef.scala#L309-L316 journalに追加 するだけ entryは現在参照中の

    Versionedと更新予定の値を 持つ入れ物
  19. 時間があれば、実装の話をしたい - synchronized block内でversionチェック関数とvalidな場合はcommitを行う https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZSTM.scala#L1752-L1754 https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZSTM.scala#L1544-L1549 https://github.com/zio/zio/blob/master/core/shared/src/main/scala/zio/stm/ZSTM.scala#L1838 isValidはjournalに保存した versionと現在のversionが同 一か調べる(expectedは

    journalに保存したversion)
  20. ご静聴ありがとうございました