LoginSignup
0
0

Swift 25 swift actor 紹介

Posted at

初めて

ストラクト化された同時性は複数のTaskを同時に実行するための強いフレトプムを提供してアフリの性能と応答性を非常に上達します。
同時性の短所の一つは複数のTaskが同一なデータを同時に接近するときに問題が発生することができるし、該当接近には読むと書きTaskが混在していることでするそのような形の問題をdata raceだと言って、偶に衝突及び推測できないアフリの動作に続けられることがあります。
以前の章には複数の同時な作業の結果を順序的に処理すると関連される問題について解決策を見てみました。
残念だけどその解決策に関連されたすべての作業は同一な作業グループにに属するに限って実際に動作する。
もっと 柔軟して同時作業を始める位置に関係なく作動する解決策は Swift Actorを使うことだ。

二十五・壱 Actor

壱・一 概要

actorは一度に1つの作業だけデータに接近されるように内部変更可能状態に対する非同期接近を制御するスイフトのプリパランスタイプでで、attribute、generator他にはmethodを含まれる点でclassと非常に似ています。これはプロトコルも遵守して拡張を書できます。Actorを宣言しするときの一番大きな違い点は 'class'の代わりに'actor'だと言う単語が使われることです。

壱・ニ 宣言する

attributeとmethodを含まれる簡単なスイフトクラスは次のように宣言します。

+ actor BuildMessage3 { // class > actor
        var message : String = ""
        let greeting = "Hello"
        
        func setName(name: String ){
            self.message = "\(greeting) \(name)"
        }
    }

actorのインスタンスは

let hello = BuildMessage()

だがクラスactorの一番大きな違い点はこれは非同期関数またはTaskのクローザー内で同じ非同期コンテキスト内だけで生成とアクセスができるということだ。またactorメソッドを呼び出しとか属性で接近するときawaitキイワード必ず使用するべきだ

  func someFunction() async{
            let builder = BuildMessage()
            await builder.setName(name:"Jane Smith")
            let message = await builder.message
            print(message)
        }

二十五・弍 data isolation

actorインスタンスで含まれたデータはアフリの他のコードと隔離されます。この様なisolationはインスタンスデータを変更(ここではname変数変形)するメソッドが呼び出されるときに、他の所のコードで該当メソッドを`呼び出されることを保証します。そうすると複数の作業が同時にデータ変更をやってみることを防止することができます。もちるんこれはメーソド呼び出すなどか属性に対する接近をできないょうに以前の作業を処理されるまで待っているべきで、await文が必要だことを意味します
また、isloationはコードがactor可変的な内部属性を直接に変更することを防止します。例えば次の様にBuildMessageインスタンスのmessage属性に新しい値を割合うコードがあったと考えてみよう。

builder.message = "hello"

クラスインスタンスを作業するときには有効するだけど、前のコードはactorインスタンスで試行するのでえーらが出るだろう
Screenshot 2023-12-06 at 3.07.26 PM.png
デフォルトでactor内のすべてのメソッドと可変的な属性はisolateされたと考慮されて、awaitキーウドを通じて呼ぶことができます。例えばgreeting文字列を返却するnonisolatedメソッドをbuildMessageactorで追加することができます。

 var builder = BuildMessage()
    
    func asyncFunction() async {
        let greeting = builder.getGreeting()
        print(greeting)
    }
    
    func sysncFunction() {
        let greeting = builder.getGreeting()
        print(greeting)
    }

この新しいメソッドは同期、非同期コンテキスト全てでawaitキイワードなくて呼ぶことができます。
getGreeting()メソッドは不便的なgreeting属性だけで接近するのせいでこのメーソドをnonisolatedだけで宣言することができます。

二十五・参 swift actor例題

以前の章にはデータ競争を調べてみたしコンファイラが次の様みたいなエラー目せじを発生することができるコードを作成しないすることを学びました。

Mutation of captured var 'timeStamps' in concurrently-excuting code

次の非同期コードを使用してディクショナリーオブジェクトで項目を書こうとする時次の様なエラーが発生しました。

struct ContentView: View {
    
    func doSomething() async{
        var timeStamps: [Int: Date] = [:]
        
        await withTaskGroup(of: Void.self){group in
            for i in 1...5 {
                group.addTask {
                    timeStamps[i] = await takesTooLong()
                }
            }
        }
    }

その様の問題を避けるための一つのオプションで以前の章で実装した方法はfor-awaitルーフを使用者して非同期作業の結果を順次的に処理することだ。だがその章で見た様にactorを使用して解決することができることである。

Xcodeで ConcurrencyDemo ふろジェクトをロードしてContentView.swifファイルを編集して次のactor宣言を追加してtimeStampsデクショナりカップシュル化してデータを追加できることのメソッドを追加してみましょう。

actor TimeStore{
    var timeStamps: [Int:Date]=[:]
    func addStamp(task: Int, date: Date) {
        timeStamps[task]=date
    }

actorを宣言したので今から doSomething()メソッドを修正してaddStamp()メソッドを通じて新しいタイムスタンプを追加することができます。

二十五・肆 MainActor紹介

24章でまメーインスレッド「メインキーユウ」に対して説明しまして、UIレンダリング処理と使用者いべーんとに対する応答をどう担当するかを説明しました。また、メーインスレッドでthread・blocking作業を実行するときの危険とそうすることは実行しているプログラミングのとまる原因になることについても説明しました。前で見たよりストラクトはメーインスレッドで分離される他のスレッドで作業実行することは簡単で強いメカニズムを提供します。また説明しないものはメーインスレッドだけであるUIアプデートを実行されることです。

swiftではメインスレッドはmainActorで表現されます。これをglobalActorだと言います。なぜならメーンスレッドで実行するコードをプログラム全体でアクセスできることだからです。

アプリを開発するとき、メーンactorで実行するを欲しなコードがあるかもしれない.特に該当コードが何らかの形でUIをアプデートしなければならない場合だ。その場合@mainActor属性を使用してコードを表現されることができる。この属性は関連作業がメーンActorで実行されるべきだとを指しるためターフ・メソッド・インスタンス・関数・クローザーで使用されることができます。例え、メーインスレッドで動作する様にクラスを構成することもできます。

+@MainActor
class TimeStore {
    var timeStamps: [Int: Date] = [:]
    
    func addStamp(task: Int, date: Date){
        timeStamps[task] = date
    }
}

他の方法で単一の値とか属性をメーインスレッドで従属で表示することができます。

-
class TimeStore {
+   @MainActor var timeStamps: [Int: Date] = [:]
    
    func addStamp(task: Int, date: Date){
        timeStamps[task] = date
    }
}

もちろん、timeStampsデックショナリはメーンActorで割り当てられたので他のスレッドで接近できません。前のaddStamp()メソッドからデックショナリで新しい日付を追加しようすると、次の様なエラーが発生するだろう。Screenshot 2023-12-06 at 8.56.04 PM.png
その問題を解決するとaddStamp()メソッドも@MainActor属性を使用者して表紙されるべきです。

class TimeStore {
    @MainActor var timeStamps: [Int: Date] = [:]
    
+   @MainActor func addStamp(task: Int, date: Date){
        timeStamps[task] = date
    }
}

mainActorrunメソッドはメーンスレッドで作業を実行する様に非同期コード内で呼び出すことができます。

func runExample() async {
    await MainActor.run{
        
    }
}

要約

非同期コード作成の核心部分はデータ競争を避けることです。データ競争は二つ以上の作業が同一なデータで接近して該当作業が書き作業を実行するときで発生します。此れは同時作業が同一なデータのお互い違うバージョンを照会して作業されるデータ不一致の原因になります。

データ競争を避けるための有用な道具はSwiftのActorターフです。これは構文面で動作の面でSwiftのクラスと似ているだけどカップシュル化されたデータはアフリ内の他のコードとは別居している点が違う。もしかしてインスタンスデータを変更するActorのメソッドが呼びだされると、該当メソッドがコードの上で他のところで呼び出される様にされる前にメソッドが完全に実行されることを保証する。これは複数の作業が同時に同一なテータを変更されない様に防止する。Actorメソッド呼び出すと属性に対する接近はawaitキーウドを使って呼び出レルベキです。

メーンActorは非同期コード内でメーンスレッドに対する接近を提供する特別なActorです。`@MainActor属性は関連された作業がメーンスレッドで実行されるべきだとを表すためターフ、メソッド、インスタンス、ファンション、くろーさを表示される様に使われることができます。

0
0
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
0