最新のSwiftのリリースであるSwift 5.10には、数点の新しい提案が含まれている。しかしながら、このアップデートは言語の並行処理モデルにとって重要な成果を示しており、これによりコンパイラ・レベルで完全なデータ分離を保証できるようになったと、SwiftチームのエンジニアであるHolly Borla氏は説明する。
Borla氏が語るように、Swiftの同時実行モデルは、Swift 5.5 でasync/await
、アクター、構造化同時実行を導入して以来、Swift 5.7でスレッドセーフ型の基礎としてSendable
プロトコルを採用し、Swift 5.10でコンパイル時に完全なデータ分離を実現するまで成熟してきた。
Swift 5.10は、言語の隅々までデータレースセーフのセマンティクスを完成させ、完全な並行性チェックの保証を強化するために、
Sendable
とアクターの分離チェックにおける多数のバグを修正しました。
実際、Swift 5.10コンパイラはコンパイル時に潜在的なデータレースを検出する新しいフラグ-strict-concurrency=complete
を追加した。これは、Swift 5.9を使用しているときに実行時に検出され、アサートが生成された分離違反が、5.10コンパイラによって潜在的なプログラミング・エラーとしてフラグ付けされ、警告が生成されることを意味する。
以前よりも厳格な新しい動作は、誤検出の可能性を含んでいる。コンパイラにより、正しいコードに対して誤ってフラグ付けされうるということだ。Borla氏が述べているように、これは基本的にコンパイラが行う解析の量を減らす必要があるためで、コンパイル時間という点でコストがかかるが、今後の言語リリースでは改善される予定だ。
このようなケースに対処するため、特定のアクターやSendable
プロトコルを実装するクラスに対してnonisolated(unsafe)
や@unchecked Sendable
を使用することで、完全なデータ分離チェックをローカルで無効にすることができる。もちろん、これは自身のプログラムをunsafeな状態にすることになるため、完全なデータ分離チェックをオプトアウトする際には自分が何をしているのかをよく理解しておく必要がある。iOS開発者であり、Swiftの書籍の著者でもある、Donny Wals氏はこのように提案している。
nonisolated(unsafe)
を使おうと考えた時は必ず、あなたがマークしている型を実際にグローバル・アクタに隔離可能かどうか、あるいはプロパティの型をSendable
にしてimmutableにすることが可能かどうかを常に自問するべきでしょう。
Sendable
と一緒にimmutable状態を使用するか、@MainActor
を使用してグローバルアクターで共有状態をカプセル化することは、Swift 5.10コンパイラが安全でないとみなすことなく、共有状態に同時にアクセスできる唯一の2つの方法である。
unsafeのopt-outディレクティブが必要な1つの顕著なケースは、DispatchQueueのセマフォを使用してレガシーコードをコンパイルして、手動で分離を確保する場合である。
前述したように、Swift 5.10の同時実行モデルは、データ・レースの誤検出が多すぎる可能性があるという点で、まだ完璧ではない。Borla氏によると、Swiftチームは次のApple WWDCカンファレンスで発表されると思われる"Swift 6"のリリースに向けて、このモデルの改善に積極的に取り組んでいるという。