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

Swift Concurrency入門

Sato Takeshi
February 22, 2022

Swift Concurrency入門

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

発表資料

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 @
    オンライン

    View Slide

  2. Who am I

    Name
    ● 佐藤タケシ
    (
    さとうたけし
    )

    Company

    Merpay, Inc.(2019/01 ~)

    Role

    Software Engineer (iOS)

    Account

    Twitter: @hatakenokakashi

    Facebook:
    佐藤剛士

    GitHub: SatoTakeshiX

    View Slide

  3. ● 一冊で
    Swift Concurrency
    の概
    要を理解ことを目指して書いて
    います
    ● まだ執筆中

    Swift Concurrency
    は新しい概
    念が盛りだくさん
    ● 覚えればあなたの開発がより安
    全に、簡単に実装できるように
    なる
    「Swift Concurrency入門」で技術
    書典で販売予定

    View Slide

  4. Swift
    Concurrency

    Swift 5.5
    から導入

    Xcode 13
    から利用可能
    ● 非同期処理が簡潔、安全に

    async/await

    Swift
    にやってき
    た!

    View Slide

  5. コールバックによる
    非同期処理の
    欠点

    View Slide

  6. ネストが深くなる

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  10. async/awaitで解決

    View Slide

  11. async/awaitで非同期処理

    async
    で非同期関数を定義

    View Slide

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

    View Slide

  13. 非同期関数

    async
    がつけられた関数・メソッド
    ● プログラムを待機、再開させる
    ● 通常のコードと同じように記述ができる
    ○ 呼び出し元で、変数の代入や
    try-catch
    によるエラーハンドリング
    ○ 戻り値を定義できるのでコールバックのよう呼び忘れがない。コンパイルの
    チェックが入る
    ● スレッドは
    CPU
    のコア数分用意される
    ○ システムが管理し、開発者が直接触ることはない

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    スレッド
    1
    スレッド
    2

    View Slide

  25. データ競合(Data Race)

    View Slide

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

    View Slide

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

    Actor
    隔離(
    Actor isolated)
    と呼ぶ

    data race
    を防ぐ
    ● 外からアクセスする場合は
    await
    が必要
    ● イニシャライザー、プロパティ、メソッド定義、プロトコル適応など
    class, struct,
    enum
    を同じ特徴をもつ

    View Slide

  28. actorでデータ競合を防ぐ

    View Slide

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

    View Slide

  30. actorで競合状態(Race Condition)は防げない
    ● 競合状態
    (Race Condition)
    マルチスレッドにおける典型的な不具合の一つ
    ● プログラミングの実行結果が各スレッドの実行順に依存する状態
    ○ 同じ入力を与えても異なるデータを出力する状態

    View Slide

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

    View Slide

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

    View Slide

  33. actorで競合状態(Race Condition)は防げない
    1.
    ③、④が同時に呼び出す
    2.
    キャッシュはまだない
    3.
    ③が①に到達。待機
    4.
    ④が①に到達。待機
    5.
    ③が再開。👾を返す。
    6.
    ③が②に到達。
    return
    する
    7.
    ④が再開。🎃を返す。
    8.
    ④が②に到達。
    return
    する
    9.
    ③、④同じ
    URL
    なのに違うコ
    ンテンツが返される=>競合
    状態

    View Slide

  34. 競合状態(Race Condition)の修正

    await
    の後でプロパティの
    チェックする
    ● Protect mutable state
    with Swift actorsに
    Task
    を使った例もあり

    View Slide

  35. MainActor
    ● メインスレッドで実行される特別な
    Actor

    Global Actor
    の一種
    ○ むしろメインスレッドのために
    Global Actor
    が提案された
    ○ 共有の
    actor
    インスタンスを通して
    Actor
    分離がされる

    @MainActor
    で型全部、プロパティのみ、メソッドのみなど適応できる

    View Slide

  36. MainActorの適応方法

    MainActor
    の適応手順をコードで示す

    View Slide

  37. Task

    View Slide

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

    Task Tree
    とよばれる親子関係を構築する

    Task Tree
    のおかげでキャンセルや優先度をシンプルにハンドリング可能
    ○ 従来の方法だとあるスレッドの処理がキャンセルされた場合に他のスレッドの処
    理に伝播させるのが難しかった

    View Slide

  39. Task Tree
    ● ①一番下位のタ
    スクがすべて終わ
    ると上位のタスク
    が始まる
    ● ②子タスクが終わ
    ると親タスクに伝

    ● ③親タスクが実行

    View Slide

  40. Task Tree
    ● ①がエラー
    ->
    兄弟
    タスクはキャンセ
    ル②
    ● 上位のタスク③が
    キャンセル。兄弟
    タスク④もキャン
    セル
    ● ④の下位タスク⑤
    もキャンセル
    ● ⑥親タスクに①の
    エラー伝播

    View Slide

  41. async letバインディングとTask Tree

    View Slide

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

    View Slide

  43. 同期関数から非同期関数を呼ぶ方法
    Task
    イニシャライザー
    ● 非同期コンテキストを提供
    ● 同期関数内から非同期関数を呼べる
    ● コールバックはすぐに呼ばれる
    ● 返り値の
    Task
    インスタンスからマニュアルで
    キャンセルできる
    ● 親タスクの優先度や
    actor,
    タスクローカル値
    を引き継ぐ
    Task.detached
    ● 非同期コンテキストを提供
    ● 同期関数内から非同期関数を呼べる
    ● コールバックはすぐに呼ばれる
    ● 返り値の
    Task
    インスタンスからマニュアルで
    キャンセルできる
    ● 親タスクの優先度や
    actor,
    タスクローカル値
    を引き継がない

    View Slide

  44. TaskイニシャライザーとTask.detached

    Task.detached

    MainActor
    を引き継
    がない
    ->
    ログ送信な
    どメインスレッドで不
    要な処理に向く

    Task

    MainActor

    引き継ぐ
    ->
    メインス
    レッドで実行

    View Slide

  45. マニュアルキャンセル

    Task
    のイニシャライザーを保持しておけば、キャ
    ンセルが必要なときに
    cancel
    メソッドでキャンセル
    できる

    View Slide

  46. キャンセルのハンドリング

    checkCancellation: Task

    キャンセルされている場合に
    CancellationError
    を返す
    ○ キャンセルを呼び出し元
    に伝える

    isCancelled:
    キャンセルかど
    うか
    Bool
    値で判断
    ○ キャンセル時追加処理が
    可能
    独自の追加処理

    View Slide

  47. iOS 13, 14で非同期関数を使う

    View Slide

  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
    パッケージの不具合を修正

    View Slide

  49. iOS 13, 14で非同期関数を使う
    ● 言語機能としての
    Swift Concurrency
    機能は使える

    Foundation
    での非同期関数は
    iOS 15
    以上

    URLSession

    data
    メソッドなど

    withCheckedThrowingContinuation

    withCheckedContinuation
    で既存の
    コールバック関数を非同期関数にラップができる
    ● アプリサポートバージョンが
    iOS 15
    が下限になるまではラップした関数を呼び出

    View Slide

  50. withCheckedContinuation
    ● エラーをスローするしないコールバック関数を非同期関数にラップする
    ● クロージャー内でラップする関数を呼ぶ
    ● ラップする関数のコールバック内で
    continuation
    は確実に一回
    resume
    メソッドを
    呼び出す
    ○ 呼び出さないのはだめ
    ○ 2回以上呼び出すのもだめ

    View Slide

  51. withCheckedContinuation

    View Slide

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

    resume(returning:)
    メソッド
    ○ ラップした関数の戻り値を引数にする

    resume(with:


    Result
    型で返す
    ● continuation.resume(throwing:)
    ○ エラー型で返す

    View Slide

  53. withCheckedThrowingContinuation

    View Slide

  54. まとめ

    View Slide

  55. まとめ

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

    iOS 13, 14
    でも
    Swift Concurrency
    は使える

    View Slide

  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

    View Slide