S_Shimotori’s diary

雰囲気で生きている

Swiftの並行処理について発表する時に描く図

🧵この記事読んでもSwiftがわかるようにはならないよゴメンネ🧵

qiita.com

皆さんはSwiftの並行処理の仕組みについて執筆したり発表したりしたことはありますか?私はあります。

文章に加えて図解もできると読者/聴衆の助けになるでしょう。てゆーか図描かないと自分でも何言ってるかわかんね。

モチベーション

ここ数ヶ月くらい、Synchronizationについて調べています。

developer.apple.com

自分の理解が正しいかどうかを確かめるために、そしてわからないことをみんなに聞くためにわいわいswiftc #42 オフライン @ メルカリ - connpassで発表しました。
(そしてやはり間違っていたのだった)

そうすると、複数のスレッドからメモリ上の値を操作する話をしなくてはいけません。 async / await で非同期関数を呼び出したときのスタック領域&ヒープ領域の操作の話もしなくてはいけません。

そんなの言葉で説明できるかーっ!

「Atomic Aはバイナリセマフォで、共有資源であるAtomic Bの排他制御を行っている。実際にはアウトオブオーダ命令によりアトミック操作の順が前後することがある。データ競合を防ぐためには適切なオーダリングでアトミック操作を行わなければならない。」
「変数 Atomic<Value> のメモリは、中断ポイントの有無や宣言と中断の順番にかかわらず常に安定している。」
って言葉だけで説明されたら辛いでしょ!自分でも何言ってるかわかんね。特に後者は今もわからない。てゆうか内容あってんのかな。

必要な図

  • 複数スレッド上の並行処理の表現
  • メモリ上の値に対する操作
  • スタック領域とヒープ領域上の様子

あとはSynchronizationとの比較として

  • アクターのタスク実行の様子

もあるとよし。

どんな図を描くべきか

読者/聴衆が一瞬で理解できるような図。
図に使っている記号やアイコンや矢印について、あまり定義したり注釈したりしなくても自然と理解してくれるような図。
同じ形の図形や矢印には同じ意味を持たせる。複数の意味を持たせない。

つまり慣習に則ってWWDC動画と同じ図を描けば解決!

マルチスレッド

まずはスレッドの図から。

WWDC動画でお馴染み。

色(#284363)の長方形がスレッド1つぶん、色(#5687C4)の長方形が同期関数で、横方向が時間経過。時間の移り変わりとともにそのスレッドを使っている関数も変わる。

🧵の絵文字は…GitHub - googlefonts/noto-emoji: Noto Emoji fontsとかでいいかな。U+1F9F5、つまり noto-emoji/svg/emoji_u1f9f5.svg at main · googlefonts/noto-emoji · GitHubが🧵画像だ。

メモリ上の値の操作

このスレッドの図に加えて、メモリ上の値の変化も表現したい。次のような図を並行処理分野で見たことがあるだろうか。人によってはシーケンス図っぽく縦向きで書くかもしれない。

横軸が時間経過を表しているのはスレッド画像と同じ。縦方向(時間経過の垂直方向)の矢印は共有資源に対する読み書きやメッセージを表す。

この「Aさん」「Bさん」のところをWWDC動画お馴染みの図🧵に差し替えてしまおう。それと、共有資源がただの横軸まっすぐな状態だと変化が見分かりづらいのでいっそ2次元グラフを描く。

これで「+=1を2回やったのに+2されてないじゃん!!!」というのが伝わりやすくなってたらいいな。

happens before/after

Synchronizationが Atomic を擁する関係で、アウトオブオーダ実行で操作順と結果反映順が一致しない様子も描きたい。どう描いたものか……。一貫性モデルの図解が少ないのでデファクトスタンダード的存在がどれなのかわからんのです。

こちらの記事がわかりやすかったのでこれに従おうと思う。
qiita.com

こんな描き方をするようだ。

操作開始の点、操作完了の点、そして結果の点がある。諸事情につき結果の点が開始〜完了の範囲に収まったり収まらなかったりする。なかなか厄介。

オーダリングを語るためにはスレッド2つと共有資源2つを登場させる必要があり、図の描き方に迷う。これでどうだ:

ちなみにこの pop() _consumerCount _lastSE-0410に出てくるやつ。破線矢印の書き方は改善の余地ありかもしれないがどうしたらいいか悩んでいる。

スタック領域とヒープ領域

(再掲)
「変数 Atomic<Value> のメモリは、中断ポイントの有無や宣言と中断の順番にかかわらず常に安定している。」

正直この説明自体が合っているか自信がない……。とにかく、変数 Atomic<Value> はスタック領域とかヒープ領域とかそういうところにいるはず。

スタック領域&ヒープ領域をSwift concurrency: Behind the scenes - WWDC21 - Videos - Apple Developer(929秒あたりから)の図を参考に描く。

この図、本当にあってるかなあ……。

変数の居場所を示すのに一旦⚛️をつけておいたが多分意味わかんないのでやめたほうが良さそう。
noto-emoji/svg/emoji_u269b.svg at main · googlefonts/noto-emoji · GitHub

アクター

比較としてアクターの図も載せたい。ここの counter はアクターが持つプロパティと思ってほしい(例:Swiftアクターによるミュータブルステートの保護 - WWDC21 - ビデオ - Apple Developerの389秒ごろ)。

Swiftの並行処理を視覚化して最適化する - WWDC22 - ビデオ - Apple Developer(851秒ごろ)を真似て描いてみた。色(#5FB061)の長方形はアクターとタスク。そしてまたまた色(#284363)の長方形が登場しているが、これはスレッドなのだろうか……。そうだとしたら空いた隙間には他のタスクやら何やらが詰まっているはず?

まとめ 感想

むずかしー。

↓近いうちにお披露目しようと思っています。レビューしてくれる人はいつでも募集です。

来年もよろしくお願いします。