Swift 6は、アプリケーションにおける共通点に対する新しいアプローチを導入しました。この記事では、解決することを目指す問題を調べ、帽子の下でどのように機能するかを説明し、新しいモデルを前のモデルと比較し、Actorモデルをより詳しく見る予定です。 Swift Concurrency Overview: Problems and Solutions 同時にタスクを実行するコードを書くことは、パフォーマンスと反応性を向上させることができますが、しばしばレース条件、ドームロック、およびトリッドセキュリティの問題などの複雑さと微妙なバグを導入します。 Swift 6 で導入された Swift Concurrency は、アシンクロンのタスクを処理するための明確で安全で効率的なモデルを提供することによって、同時プログラミングを簡素化することを目指しています. It helps developers avoid common pitfalls by enforcing strict rules around data access and execution order. 💡 Swift 5.x を使用して Swift 6 に移行する計画がある場合は、プロジェクト設定で Swift Concurrency チェックを有効にすることができます。これにより、既存のコードとの互換性を維持しながら、新しいコンピューレーション モデルを徐々に採用できます。これらのチェックを有効にすると、潜在的なコンピューレーション 問題を早期に把握し、移行をよりスムーズに、より安全にできます。コードベースを更新するにつれて、完全な書き換えなしに、async/await シンタクスや他の Swift Concurrency 機能を段階的に統合し始めることができます。 💡 Swift 5.x を使用し、Swift 6 に移行する計画がある場合は、プロジェクト設定で Swift Concurrency チェックを有効にすることができます。これにより、既存のコードとの互換性を維持しながら、新しいコンポーネント モデルを徐々に採用できます。これらのチェックを有効にすると、潜在的なコンポーネント 問題を早期に把握し、移行をスムーズにし、より安全にすることができます。 async/await syntax とその他の Swift Concurrency 機能は、完全な書き換えなしに段階的に増加します。 Some of the key problems Swift Concurrency addresses include: レース条件:予測不能な行動を引き起こす可能性のある共有変異状態への同時にアクセスを防ぐ。 コールバック地獄:以前は組み込まれたコールバックや完了処理に大きく依存していた非同期コードを単純化し、コードを読み取り、維持しやすくします。 トレード管理の複雑さ:低レベルの作成と同期を抽象化し、開発者がトレード処理よりも論理に焦点を当てることを可能にします。 同期タスクの調整:構造化された同期は、適切なキャンセルとエラーの拡散を伴うタスクの明確な階層を可能にします。 新しい言語機能を活用することで、例えば、 Swift 6 は、同時にコードを書くより直感的で強力な方法を提供し、開発者の生産性とアプリの安定性を向上させます。 async/await Multitasking 現代のオペレーティングシステムとランタイムは、複数の作業単位を同時に実行するためにマルチタスクを用います。Swift Concurrencyは、OSレベルのトレードで使用される予防的なマルチタスクモデルと根本的に異なる協力型マルチタスクを採用しています。 予防マルチタスク Preemptive multitasking は、オペレーティング システムがトレードとプロセスを管理するために使用するモデルです. In this model, a system-level scheduler can forcibly interrupt any thread at virtually any moment to perform a context switch and allocate CPU time to another thread. This ensures fairness across the system and allows for responsive applications — especially when handling multiple user-driven or time-sensitive tasks. このモデルでは、システムレベルのスケジュールは、ほぼいつでもどのトレードを強制的に中断して、コンテキスト スイッチを実行し、別のトレードに CPU 時間を割り当てることができます. Preemptive multitasking enables true parallelism across multiple CPU cores and prevents misbehaving or long-running threads from monopolizing system resources. However, this flexibility comes at a cost. Because threads can be interrupted at any point in their execution — even in the middle of a critical operation — developers must use synchronization primitives such as mutexes, semaphores, or atomic operations to protect shared mutable state. Failing to do so may result in data races, crashes, or subtle bugs that are often difficult to detect and reproduce. このモデルは、より大きなコントロールと一貫性を提供しますが、開発者に大幅に大きな負担を課します。予防的な環境でのトレードの安全性を確保することは、エラーに敏感であり、非決定的な行動 - 実行から実行に異なる行動 - を引き起こす可能性があります。 技術的な観点から言えば、予防的マルチタスクは、トレイドの実行を処理するオペレーティングシステムに依存します。 OS は、ほぼすべての点でトレイドを中断し、機能の真ん中でも、別のトレイドに切り替えることができます。これを行うには、システムは、現在のトレイド(CPU レジストリ、指示ポインタ、スタックポインタ)の実行全体を保存し、別のトレイドの以前に保存された状態を回復することを含むコンテキスト スイッチを実行する必要があります。このプロセスでは、CPU キャッシュを洗浄し、Translation Lookaside Buffer (TLB) を無効にし、ユーザーモードとカーネルモードの間を切り替えることも 各コンテキスト スイッチは時間とシステムリソースを消費する - 特にコンテキスト スイッチが頻繁に発生する場合や、多くのトレードが制限された CPU コアに競合する場合。 このモデルは最大限の柔軟性と真の並列性を提供しますが、タスクは通常、CPUを積極的に使用するのではなく、I/O、ユーザ入力、またはネットワーク応答を待つ時間の大半を費やしている非同期のワークフローではしばしば過剰です。 コラボレーションマルチタスク 対照的に、Swift の concurrency ランタイムでは、協力型マルチタスクを用います. In this model, a task runs until it voluntarily yields control — typically at a wait point or via an explicit call to 従来のトレードとは異なり、協力タスクは決して強制的に制限されることはありません. This results in predictable execution: context switches occur only at clearly defined suspension points. Task.yield() Swift のコラボレーション タスクは、グランド セントラル ディスパッチの列から別々に、軽量でランタイム管理されたコラボレーション トレッド ポールにスケジュールされています。このポールで実行されるタスクは「良い市民」で、特に長時間実行またはCPU 密集した作業中に、適切なときにコントロールを提供する予定です。 マニュアル停止ポイントとして、他のタスクが実行される可能性を確保します。 Task.yield() しかし、協力型マルチタスクは警告を伴います:タスクが決して停止しない場合、それが実行されているスレッドを独占し、システム内の他のタスクを遅らせたり、飢えさせたりする可能性があります。 協力型マルチタスクでは、実行の基本単位は糸ではなく、仕事の一部であり、しばしば継続と呼ばれる。 Function Suspended at an , the Swift runtime captures the current execution state into a heap-allocated continuation. This continuation represents a resumption point and is enqueued for future execution. Swift runtime captures the current execution state into a heap-allocated continuation. This continuation represents a resumption point and is encased for future execution. Swift runtime captures the current execution state into a heap-allocated continuation. This continuation represents a resumption point and is encased for future execution. async await 長期間にわたるタスクとトレードを関連付ける代わりに、Swift ランタイムはトレードを継続のパイプラインとして扱います. Each thread executes one continuation after another. When a continuation finishes or suspends again, the thread picks up the next ready continuation from the queue. 上記のように、このモデルは、従来のOSレベルのコンテキスト スイッチを避ける。 CPU レジストリやトレード スタックを保存して復元する必要はありません; ランタイムは単に次の閉鎖のような継続を呼び起こします。 キーコントロール:メモリを少し使いますが、タスク管理のためのオーバーヘッドが劇的に低くなります。 協力スケジュールは、停止が発生したときに厳しい制御を提供し、予測性を向上させ、同時に推論しやすくなります。 を導入する Task タスク スピードコンテストA asynchronous work を単に呼び出すこととは異なり、 機能 A is a managed object that runs simultaneously with other tasks in a cooperative thread pool. コペラティブ・トレード・ポール内の他のタスクと同時に実行される管理対象です。 Task async Task 💡 Tasks are managed by a cooperative thread pool. The cooperative thread pool is designed to manage concurrency efficiently by allowing tasks to yield the CPU while waiting for asynchronous operations to complete. This is achieved through the use of async functions and tasks, which are the fundamental units of concurrency in Swift. 💡タスクは協同トレイドプールによって管理されます。協同トレイドプールは、タスクが非同期操作が完了するのを待ちながらCPUを生成することを可能にすることにより、効率的に同期を管理するように設計されています。 タスクは同時に実行するように作成することができ、待機またはキャンセルすることもできます。それらはアシンクロンの行動に対する精密な制御を提供し、Swift で構造化された共通の不可欠な部分です。 創るA Task A task can be created using the , which immediately launches the provided asynchronous operation. 次のように表示されます。 Task initializer 初心者 Task(priority: .userInitiated) { await fetchData() } あなたが創造するとき A スタンダード・イニシアライザー(No Initializer) )は、周囲の俳優の文脈、優先順位、およびタスクローカル値を相続します. This behavior is crucial for structured concurrentness and security in concurrent code. Task detached 分離 💡 Swift 6.2 は、同期の処理方法に大きな変更を導入します:デフォルトでは、すべてのコードが MainActor で実行されます。 背景でコードを実行するには、Swift 6.2 は新しい属性 @concurrent を追加します。 💡 Swift 6.2 は、同期の処理方法に大きな変更を導入します: 既定では、すべてのコードが実行されます。 MainActor 背景でコードを実行するには、Swift 6.2 が新しい属性を追加します。 @concurrent . you can also use nonisolated コードが主役へのアクセスを必要としない場合:WWDC Embracing Swift Concurrency WWDC、Swiftコンクールを採用 WWDC、Swiftコンクールを採用 帽子の下で、Swift Concurrencyの以前のバージョンでは、Swift ランタイムは内部メカニズムを用いた。 このプロパティはパブリック API の一部ではなかったが、俳優隔離されたコード内で作成されたタスクが同じ俳優で実行され、データレースのセキュリティを維持するために重要な役割を果たした。 @_inheritActorContext Swiftの進歩により、ランタイムは移行を開始しました。 新たに知られる機械として、 現在では、コンパイラとランタイムによってより明確に処理されています。 @_inheritActorContext sending 💡送信とは何ですか?送信は、Swift 6に導入された新しいキーワードであり、言語がより安全で明確な共通点に向かう一環として使用されています。それは、共通点の境界を越えて移動する機能パラメータをマークし、値を返すために使用されています。それは特によく動作し、メモリの安全性を確保し、使用後の移動エラーを防ぐ。パラメータが送信でマークされると、コンパイラは、転送後に元のインスタンスにアクセスできないことを強制します。 func process(_ data: sending MyNonCopyableType) async { // `data` is moved here and can’t be used elsewhere after the call } 何が sending ? sending Swift 6 で導入された新しいキーワードは、言語がより安全で明確な共通語に移行する一環として、機能パラメータをマークし、共通語の境界を越えて移動する値を返すために使用されています。 sending , the compiler enforces that the original instance is no longer accessed after the transfer. func process(_ data: sending MyNonCopyableType) async { // `data` is moved here and can’t be used elsewhere after the call } あなたがAを打ち上げるとき , タスクによってキャプチャされたすべての値が コンパイラはこれをコンパイラタイムで実行します。 プロトコルおよび 機能タイプ Task.detached Sendable Sendable @Sendable に合致しないこと コンパイルタイムエラーを引き起こす可能性があります、特に厳格なコンパイルモードでは。 Sendable タスクも優先順位をサポートし、Grand Central Dispatch の列がそれらを処理する方法に似ています。 vs Task Task.detached Swift Concurrency で働くとき、その違いを理解することが重要です。 そして , as they define how and where asynchronous work is executed. as they define how and where asynchronous work is executed. as they define how and where asynchronous work is executed. Task Task.detached Task タスク 現行の演技場(たとえば、 それは一般に、現在の構造化した同期の木または同期の分離を尊重する新しい同期操作を生み出したいときに使用されます。 Task MainActor Task { await updateUI() } 上記の例では、主役から呼ばれた場合、 主人公が明示的に別の場所に移動しない限り、同様に実行されます。 Task Task.detached トップ > デトックス creates a completely independent task. It doesn’t inherit the current actor context or priority. This means it starts in a global concurrent context and requires manage safety, especially when accessing shared data. Task.detached Task.detached { await performBackgroundWork() } 利用 現在の構造化された文脈の外でバックグラウンド操作を実行する必要がある場合、例えば長期的に実行される計算や、俳優の孤立から逃れる。 Task.detached Cooperative Thread Pool Swift Concurrency の Cooperative Thread Pool は、CPU コアの数に匹敵する限られた数にそれらをスケジュールすることによって非同期タスクの実行を管理するメカニズムです。 Swift Concurrency の Cooperative Thread Pool は、CPU コアの数に匹敵する限られた数にそれらをスケジュールすることによって非同期タスクの実行を管理するメカニズムです。 Swift Concurrency は、効率的なスケジュールと最小限のスレッドオーバーヘッドのために設計されたコラボレーション トレッド ポールを使用して動作します。 一般的な過剰な単純化は、Swift Concurrency はコアごとに 1 つのトレードを使用し、コンテキストの切り替えを削減し、CPUの利用を最大化するという目標と一致しています。 Thread Count: Not So Simple Thread Count: Not So Simple 16-core Mac では、GCD の関与なしに、Swift Concurrency が単独で管理する 64 トレードまで観察することが可能である。 正式: Max threads = (CPU cores) × (dedicated quality-of-service buckets) 従って、16コアシステムでは、 16 cores × 4 QoS buckets = 64 threads 各 QoS バケットは、本質的に類似の実行優先度を共有するタスクのグループのための専用トレッド レーンであり、これらはダーウィンのトレッド スケジュールメカニズムによって内部で管理され、GCD 列とは異なります。 QoSバケットとタスク優先度 QoSバケットとタスク優先度 たとえ 6つの常数を明らかにし、そのうちのいくつかは代名詞である。 TaskPriority トップ > ハイ 役に立つ低 デフォルト → already mapped to medium カーネルの視点では、それぞれQoSバケットにマッピングされた4つのコア優先レベルに簡素化され、これは協力トレイドプールにおけるトレイドの割り当てに影響を与えます。 過労はいつ起きるの? 過労はいつ起きるの? 通常の負荷では、Swift Concurrency は協力プールの限界を尊重します。しかし、議論(例えば、優先順位の高いタスクが低優先順位のタスクを待っている場合)では、このダイナミックな調整は、時間に敏感なタスクが低優先順位の仕事の後ろに無期限にブロックされないことを保証します。 この行動は、Machのスケジュールポリシーと高優先性を通じて、ダーウィン・カーネルによって管理されます。 ライン - あなたのコードによって明示的に制御されるものではありません。 pthreads 優先課題 Swift は、Grand Central Dispatch (GCD) と同様に、タスクの優先順位システムを提供しますが、構造化された同期モデルによりセマンティックに統合されています。 初心者: Task Task(priority: .userInitiated) { await loadUserData() } 利用可能な優先順位は、 enum: TaskPriority Priority Description / .high .userInitiated For tasks initiated by user interaction that require immediate feedback. .medium For tasks that the user is not actively waiting for. / .low .utility For long-running tasks that don’t require immediate results, such as copying files or importing data. .background For background tasks that the user is not directly aware of. Primarily used for work the user cannot see. / / .high .userInitiated 即時フィードバックを必要とするユーザーインタラクションによって開始されたタスク。 .medium For tasks that the user is not actively waiting for. / / .low .utility For long-running tasks that don’t require immediate results, such as copying files or importing data. .background ユーザーが直接知らないバックグラウンドのタスクのために、主にユーザーが見ることができない作業に使用されます。 さまざまな優先順位を持つ課題の作成 さまざまな優先順位を持つ課題の作成 When you create a 別のタスク(デフォルト) 優先順位)は、それぞれのネストされたタスクに明示的に異なる優先順位を設定できます。 , and the other is .high. This demonstrates that priorities can be individually set regardless of the parent. これは、親に関係なく個別に優先順位を設定することができることを示しています。 Task .medium .low Task { // .medium by default Task(priority: .low) { print("\(1), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } Task(priority: .high) { print("\(2), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } } // 1, thread: <_NSMainThread: 0x6000017040c0>{number = 1, name = main}, priority: TaskPriority.low // 2, thread: <_NSMainThread: 0x6000017040c0>{number = 1, name = main}, priority: TaskPriority.high 組み込まれたタスクの優先順位を明示的に設定しない場合、そのタスクはその親の優先順位を相続します。 そして ブロックは、優先順位が上昇しない限り、これらの優先順位を相続する。 .high .low 優先順位は相続できる。 優先順位は相続できる。 Task { Task(priority: .high) { Task { print("\(1), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } } Task(priority: .low) { print("\(2), "thread: \(Thread.current)", priority: \(Task.currentPriority)") Task { print("\(3), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } Task(priority: .medium) { print("\(4), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } } } // 2, thread: <_NSMainThread: 0x600001708040>{number = 1, name = main}, priority: TaskPriority.low // 1, thread: <_NSMainThread: 0x600001708040>{number = 1, name = main}, priority: TaskPriority.high // 3, thread: <_NSMainThread: 0x600001708040>{number = 1, name = main}, priority: TaskPriority.low // 4, thread: <_NSMainThread: 0x600001708040>{number = 1, name = main}, priority: TaskPriority.medium インストールされたタスクの優先順位を明示的に設定しない場合は、その優先順位はその直近の親の優先順位を相続します. In this example, the anonymous tasks within .high and .low blocks inherit those respective priorities unless overridden. エスカレーションの優先順位 エスカレーションの優先順位 Task(priority: .high) { Task { print("\(1), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } await Task(priority: .low) { print("\(2), "thread: \(Thread.current)", priority: \(Task.currentPriority)") await Task { print("\(3), "thread: \(Thread.current)", priority: \(Task.currentPriority)") }.value Task(priority: .medium) { print("\(4), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } }.value } // 1, thread: <_NSMainThread: 0x6000017000c0>{number = 1, name = main}, priority: TaskPriority.high // 2, thread: <_NSMainThread: 0x6000017000c0>{number = 1, name = main}, priority: TaskPriority.high // 3, thread: <_NSMainThread: 0x6000017000c0>{number = 1, name = main}, priority: TaskPriority.high // 4, thread: <_NSMainThread: 0x6000017000c0>{number = 1, name = main}, priority: TaskPriority.medium このメカニズムは優先順位のエスカレーションと呼ばれ、優先順位の高いタスクがタスクを待っているとき、システムは一時的に優先順位を上げてボトルネックを回避し、応答性を確保することができます。 結果として: タスク 2 は .low で、待機中に .high にエスカレートします。 明示的な優先順位を持たないタスク 3 は、マザー (タスク 2) からエスカレート優先順位を相続し、また .highpriority で実行されます。 タスク 4 は .medium に優先順位を明示的に設定し、エスカレーションによって影響されないようにします。 優先順位を相続しない Task.detached Task.detached 課題の分割( ) 独立して実行し、親任務の優先順位を相続しない. 彼らは独自のスケジュールでグローバルタスクのように振る舞う. これは背景作業を分離するのに役立ちますが、手動で設定されない場合に予期せぬ優先順位の不一致をもたらす可能性があります. Task.detached Task(priority: .high) { Task.detached { print("\(1), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } Task(priority: .low) { print("\(2), "thread: \(Thread.current)", priority: \(Task.currentPriority)") Task.detached { print("\(3), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } Task(priority: .medium) { print("\(4), "thread: \(Thread.current)", priority: \(Task.currentPriority)") } } } // 1, thread: <NSThread: 0x60000174dec0>{number = 4, name = (null)}, priority: TaskPriority.medium // 2, thread: <_NSMainThread: 0x600001708180>{number = 1, name = main}, priority: TaskPriority.low // 3, thread: <NSThread: 0x60000174dec0>{number = 4, name = (null)}, priority: TaskPriority.medium // 4, thread: <_NSMainThread: 0x600001708180>{number = 1, name = main}, priority: TaskPriority.medium Suspension Points and How Swift Manages Async Execution について Swift では、いずれかの呼び出しに 機能 使用 is a potential suspension point - a place in the function where executing may pause and resume latter. それは、待望の操作が完了した後、機能の状態を保存することを含む変換である。 async await Here’s an example: func fetchData() async -> String { let result = await networkClient.load() return result } この場合、 関数がこのラインに達すると、実行を停止し、システムに制御を生成し、後で再開することがあります。 シーンの後ろで、コンパイラはこの機能を、その進捗状況と内部変数を追跡する状態マシンに変換します。 await networkClient.load() load() 『Under the Hood: Continuations and State Machines』 すべて Swiftの機能は、ステータスマシンにコンパイルされます。 転換点に到達する前に、 スピード: async await await ローカル変数と現在の指示ポインタを含む、関数の現在の状態を保存します。 執行を中止し、継続を予定する。 async 操作が完了すると、停止した場所から機能を再開します。 これは、多くの機能プログラミングシステムで使用される継続通行スタイル(CPS)に似ています. In Swift's concurrency model, this is orchestrated by internal types such as 競合時間のスケジュール ParticialAsyncTask ブロック!ブロック! あなたが Swift では、現在のトレードはブロックされていません。 await 現在のタスクは、コントロールを執行者に返します。 他のタスクは待つ間に実行できます。 待望の操作が完了すると、適切な実行者で中止されたタスクが再開されます。 This makes 基本的に、トレードベースのブロック操作よりも効率的でスケーラブルです。 . async/await DispatchQueue.sync : 他のタスクを実行する Task.yield() トップ > 出力( ) スウィフトの同期システムが提供する静的方法で、現在のタスクを自発的に停止し、システムに他の同期タスクを実行する機会を与えます。 Task.yield() func processLargeBatch() async { for i in 0..<1_000_000 { if i % 10_000 == 0 { await Task.yield() } } } なし このループは、執行者を独占するだろう。 定期的に、あなたはSwiftのコンポーネントランタイムと協力し、応答性と公平性を維持することができます。 await await Task.yield() Under The Hood 呼び出し待ち 現在のタスクを中止し、現在の実行者(たとえば、主役またはグローバル同時実行者)の列の終わりに再度実行します。 Task.yield() これは、Swiftの協力型マルチタスクモデルの一部です:タスクは次の停止点まで実行され、公平な生産を期待されます。 概要 Swift 6 は、コンポーネントがどのように処理されるかにおいて重要な一歩を踏み出し、開発者により多くのコントロール、予測性、およびセキュリティを提供します。学習曲線は最初は急落するかもしれませんが、これらのコンセプトを理解することは、高度に反応し、強力なアプリケーションを構築するための扉を開きます。