Slide 1

Slide 1 text

ZIOで触るSTM

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

(Software) Transactional Memory - 並列処理を制御するための仕組み/実装 - DBトランザクションのようなトランザクションをメモリ上のデータに対して提 供する - 悲観ロック - commit時にデータの変更を検知し、処理時とのデータの相違があれば先 頭から処理をやり直す - Software Transactional Memory(STM)はTransaction Memoryをソフト ウェア上(特定の言語上など)で実装したもの

Slide 9

Slide 9 text

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などとの相 互変改も提供されており他エフェクトラッパーとの共存や、移行などもやりやすいようになっている。

Slide 10

Slide 10 text

ZIO 長い、 三行で - 副作用をラップし、再実行可能なタスクとして変数に束縛できる - 並列処理用のモジュールが提供されている - DI機能とかも提供されている

Slide 11

Slide 11 text

ZIOで提供されているモジュール(一例) - ZIO DI機能付きエフェクトラッパー - Fiber マイクロスレッド - Ref AtomicRefalence - Semaphore セマフォ - Chunk Arrayベースのハイパフォーマンス Collection - Queue 非同期で利用可能なQueue - Managed Closableなリソースを扱うためのモジュール (≒ cats.effect.Resource) - STM 悲観ロック トランザクション - Stream stream処理

Slide 12

Slide 12 text

zio.stm.STM https://gist.github.com/keiSunagawa/13b30afae7e3b017a0ab5bdd75efa30c 口座はTRefとして表現される 口座(トランザクション処理対象の 値)を任意数作成する関数 片方の口座から出金 もう片方の口座へ入金をする トランザクション処理 STM操作を合成してひとつのトラ ンザクションを生成できる この戻り値のSTMをさらに合成し て大きなトランザクションにするこ ともできる USTM[A]はSTM[Nothing, A]の type alias

Slide 13

Slide 13 text

zio.stm.STM https://gist.github.com/keiSunagawa/13b30afae7e3b017a0ab5bdd75efa30c STM#commitを呼び出すことで トランザクションを実行できる コミット後はIOタス クになる (遅延実行) forkはprogram0の返す IOタスクを並列で実行す る

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

まとめ - STMは並列処理上に悲観ロック トランザクションを提供するもの - ユーザはロックの概念を意識せず、任意数のobjectを扱える - ZIOではSTMの実装が提供されている - DBトランザクションのようにコミット/ロールバックの概念が存在する - ロールバックが発生した場合はトランザクションの先頭から処理をやりなおす - コミット処理はsynchronized blockで実行される

Slide 17

Slide 17 text

時間があれば、実装の話をしたい - 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

Slide 18

Slide 18 text

時間があれば、実装の話をしたい - トランザクションでは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と更新予定の値を 持つ入れ物

Slide 19

Slide 19 text

時間があれば、実装の話をしたい - 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)

Slide 20

Slide 20 text

ご静聴ありがとうございました