0
1

More than 1 year has passed since last update.

actor

actorはSwift5.5から導入された、データ競合を守るための新しい型です。
データ競合とは複数のスレッドで同一のデータ領域にアクセスした場合に、データに不整合が生じることを言います。
マルチスレッドで別々の処理を並列で実行することは便利ですが、一つずつ実行する逐次的な処理ではないからこそデータ不整合には気をつける必要があります。
今回はactorを使いどのようにデータ競合から守るのか紹介していきます。

actorを使用しない場合

以下のTimeクラスのupdate処理を別々のスレッドで叩いてる処理になります。
各々のスレッド処理でupdate後にベストタイムを出力してますが、出力結果としては順不同で15.3, 13.0が出力されます。
この順不同な結果が出るのはデータ競合が起きているためです。
本来なら各々のスレッドでupdateした値が出力結果になるはずです。
それではこの処理をactorを使い修正していきます。

class Time {
    var times: [Double] = []
    private(set) var bestTime: Double = 100

    func update(with time: Double) {
        times.append(time)
        if time < bestTime {
            bestTime = time
        }
    }
}

let time = Time()
DispatchQueue.global(qos: .default).async {
    time.update(with: 15.3)
    print(time.bestTime)
}
DispatchQueue.global(qos: .default).async {
    time.update(with: 13.0)
    print(time.bestTime)
}

actorを使用する場合

以下がactorを使用した処理になります。
変更点としては、Timeをclassからactorで実装し直します。
次に呼び出し側の処理として、複数同時アクセスするためにTask.detachedを使用します。
後はactor内のプロパティ、メソッドにアクセスするためにawaitを付与します。
これでインスタンスに対し、複数同時アクセスを行なってもデータ競合が発生しません。

actor Time {
    var times: [Double] = []
    private(set) var bestTime: Double = 100

    func update(with time: Double) {
        times.append(time)
        if time < bestTime {
            bestTime = time
        }
    }
}

let time = Time()
Task.detached {
    await time.update(with: 15.3)
    print(await time.bestTime)
}
Task.detached {
    await time.update(with: 13.0)
    print(await time.bestTime)
}

参考

今回は以下の記事を参考に備忘録として簡略化してまとめました。
より細かく知りたい方は以下の記事をご覧ください。
https://blog.personal-factory.com/2022/01/16/explanation-of-actor-since-swift5_5/
https://qiita.com/h1d3mun3/items/f6ae63368e133e212115

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1