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

Swift Concurrency入門

Swift Concurrency入門

集まれSwift好き!Swift愛好会 vol.65 @ オンライン
https://love-swift.connpass.com/event/238725/

発表資料

53e2d354b3299d64a54af680865516d5?s=128

Sato Takeshi

February 22, 2022
Tweet

More Decks by Sato Takeshi

Other Decks in Technology

Transcript

  1. Swift Concurrency 入門 2022 年 2 月 22 日 集まれ

    Swift 好き! Swift 愛好会 vol.65 @ オンライン
  2. Who am I • Name • 佐藤タケシ ( さとうたけし )

    • Company • Merpay, Inc.(2019/01 ~) • Role • Software Engineer (iOS) • Account • Twitter: @hatakenokakashi • Facebook: 佐藤剛士 • GitHub: SatoTakeshiX
  3. • 一冊で Swift Concurrency の概 要を理解ことを目指して書いて います • まだ執筆中 •

    Swift Concurrency は新しい概 念が盛りだくさん • 覚えればあなたの開発がより安 全に、簡単に実装できるように なる 「Swift Concurrency入門」で技術 書典で販売予定
  4. Swift Concurrency • Swift 5.5 から導入 • Xcode 13 から利用可能

    • 非同期処理が簡潔、安全に • async/await が Swift にやってき た!
  5. コールバックによる 非同期処理の 欠点

  6. ネストが深くなる

  7. コールバックの呼び忘れ

  8. コールバックの呼び忘れ コールバックを呼ばないで returnしている

  9. 呼び出し元で不具合発生 コールバックが呼ばれないので、 エラーが起きているのに、 ローディングビューがずっと出しっぱな しになるかもしれない

  10. async/awaitで解決

  11. async/awaitで非同期処理 • async で非同期関数を定義

  12. async/awaitで非同期処理 • 呼び出し元

  13. 非同期関数 • async がつけられた関数・メソッド • プログラムを待機、再開させる • 通常のコードと同じように記述ができる ◦ 呼び出し元で、変数の代入や

    try-catch によるエラーハンドリング ◦ 戻り値を定義できるのでコールバックのよう呼び忘れがない。コンパイルの チェックが入る • スレッドは CPU のコア数分用意される ◦ システムが管理し、開発者が直接触ることはない
  14. awaitでプログラムが待機する

  15. awaitでプログラムが待機する

  16. awaitでプログラムが待機する

  17. 順次実行の実装の違い

  18. 順次実行をする by 同期関数 ネストが深くなる

  19. 順次実行をする by 非同期関数

  20. 並列実行の実装の違い

  21. 並列実行をする by 同期関数

  22. 並列実行をする by 非同期関数

  23. データ競合を防ぐ新しい型 Actor

  24. データ競合(Data Race)とは? • 複数のスレッドがデータに同時にアクセスしたためにデータが不正になる状況 ◦ スレッドの少なくとも一つが値を書き込む 値 スレッド 1 スレッド

    2
  25. データ競合(Data Race)

  26. データ競合(Data Race) playgroundで実行すると 110,110が出力される場合がある

  27. actorの特徴 • 新しい型の種類 • 参照型 • インスタンスに外からアクセスは同時にひとつのみに限定される ◦ Actor 隔離(

    Actor isolated) と呼ぶ ◦ data race を防ぐ • 外からアクセスする場合は await が必要 • イニシャライザー、プロパティ、メソッド定義、プロトコル適応など class, struct, enum を同じ特徴をもつ
  28. actorでデータ競合を防ぐ

  29. actorでデータ競合を防ぐ 必ず100, 110が順不同で出力される -> データ競合がなくなる

  30. actorで競合状態(Race Condition)は防げない • 競合状態 (Race Condition) マルチスレッドにおける典型的な不具合の一つ • プログラミングの実行結果が各スレッドの実行順に依存する状態 ◦

    同じ入力を与えても異なるデータを出力する状態
  31. actorで競合状態(Race Condition)は防げない

  32. actorで競合状態(Race Condition)は防げない

  33. actorで競合状態(Race Condition)は防げない 1. ③、④が同時に呼び出す 2. キャッシュはまだない 3. ③が①に到達。待機 4. ④が①に到達。待機

    5. ③が再開。👾を返す。 6. ③が②に到達。 return する 7. ④が再開。🎃を返す。 8. ④が②に到達。 return する 9. ③、④同じ URL なのに違うコ ンテンツが返される=>競合 状態
  34. 競合状態(Race Condition)の修正 • await の後でプロパティの チェックする • Protect mutable state

    with Swift actorsに Task を使った例もあり
  35. MainActor • メインスレッドで実行される特別な Actor • Global Actor の一種 ◦ むしろメインスレッドのために

    Global Actor が提案された ◦ 共有の actor インスタンスを通して Actor 分離がされる • @MainActor で型全部、プロパティのみ、メソッドのみなど適応できる
  36. MainActorの適応方法 • MainActor の適応手順をコードで示す

  37. Task

  38. Task • 並行処理の基本単位。すべての非同期関数は Task を通して実行される • 各 Task を Task

    Tree とよばれる親子関係を構築する • Task Tree のおかげでキャンセルや優先度をシンプルにハンドリング可能 ◦ 従来の方法だとあるスレッドの処理がキャンセルされた場合に他のスレッドの処 理に伝播させるのが難しかった
  39. Task Tree • ①一番下位のタ スクがすべて終わ ると上位のタスク が始まる • ②子タスクが終わ ると親タスクに伝

    播 • ③親タスクが実行
  40. Task Tree • ①がエラー -> 兄弟 タスクはキャンセ ル② • 上位のタスク③が

    キャンセル。兄弟 タスク④もキャン セル • ④の下位タスク⑤ もキャンセル • ⑥親タスクに①の エラー伝播
  41. async letバインディングとTask Tree

  42. async letバインディングとTask Tree 親タスク 子タスク 子タスク

  43. 同期関数から非同期関数を呼ぶ方法 Task イニシャライザー • 非同期コンテキストを提供 • 同期関数内から非同期関数を呼べる • コールバックはすぐに呼ばれる •

    返り値の Task インスタンスからマニュアルで キャンセルできる • 親タスクの優先度や actor, タスクローカル値 を引き継ぐ Task.detached • 非同期コンテキストを提供 • 同期関数内から非同期関数を呼べる • コールバックはすぐに呼ばれる • 返り値の Task インスタンスからマニュアルで キャンセルできる • 親タスクの優先度や actor, タスクローカル値 を引き継がない
  44. TaskイニシャライザーとTask.detached • Task.detached は MainActor を引き継 がない -> ログ送信な どメインスレッドで不

    要な処理に向く • Task は MainActor を 引き継ぐ -> メインス レッドで実行
  45. マニュアルキャンセル • Task のイニシャライザーを保持しておけば、キャ ンセルが必要なときに cancel メソッドでキャンセル できる

  46. キャンセルのハンドリング • checkCancellation: Task が キャンセルされている場合に CancellationError を返す ◦ キャンセルを呼び出し元

    に伝える • isCancelled: キャンセルかど うか Bool 値で判断 ◦ キャンセル時追加処理が 可能 独自の追加処理
  47. iOS 13, 14で非同期関数を使う

  48. XcodeのリリースとSwift Concurrency対応状況 • Xcode 13 ◦ 2021 年 9 月

    21 日リリース ◦ Swift Concurrency 機能は iOS 15 のみ • Xcode 13.2 ◦ 2021 年 12 月 13 日リリース ◦ Swift Concurrency 機能が iOS 13, 14 にもバックポートされた ◦ ただし Swift パッケージがビルドできない不具合が見つかる • Xcode 13.2.1 ◦ 2021 年 12 月 17 日リリース ◦ Swift パッケージの不具合を修正
  49. iOS 13, 14で非同期関数を使う • 言語機能としての Swift Concurrency 機能は使える • Foundation

    での非同期関数は iOS 15 以上 ◦ URLSession の data メソッドなど • withCheckedThrowingContinuation と withCheckedContinuation で既存の コールバック関数を非同期関数にラップができる • アプリサポートバージョンが iOS 15 が下限になるまではラップした関数を呼び出 す
  50. withCheckedContinuation • エラーをスローするしないコールバック関数を非同期関数にラップする • クロージャー内でラップする関数を呼ぶ • ラップする関数のコールバック内で continuation は確実に一回 resume

    メソッドを 呼び出す ◦ 呼び出さないのはだめ ◦ 2回以上呼び出すのもだめ
  51. withCheckedContinuation •

  52. withCheckedThrowingContinuation • エラーをスローするコールバック関数を非同期関数にラップする • クロージャー内でラップする関数を呼ぶ • ラップする関数のコールバック内で continuation は確実に一回 resume

    メソッドを 呼び出す • resume(returning:) メソッド ◦ ラップした関数の戻り値を引数にする • resume(with: ) ◦ Result 型で返す • continuation.resume(throwing:) ◦ エラー型で返す
  53. withCheckedThrowingContinuation •

  54. まとめ

  55. まとめ • async/await で非同期処理を同期関数のように記述できるようになった • それによって読みやすさが向上し、コールバックの呼び忘れなどのミスを防 げるようになった • マルチスレッドでよくある不具合、データ競合を防ぐ新しい型、 actor

    が登場 した ◦ ただし、競合状態はまだ防げない • 非同期処理は Task という単位で行われる • iOS 13, 14 でも Swift Concurrency は使える
  56. 参考資料 • Race condition vs. Data Race: the differences explained

    • データ競合 (data race) と競合状態 (race condition) を混同しない • Protect mutable state with Swift actors • https://github.com/apple/swift-evolution/blob/main/proposals/0316-glo bal-actors.md • Explore structured concurrency in Swift • Meet async/await in Swift