69 lines
3.0 KiB
Markdown
69 lines
3.0 KiB
Markdown
|
|
---
|
|||
|
|
name: swift-concurrency-6-2
|
|||
|
|
description: Swift 6.2 易用併發模式 — 預設單線程、顯式標註 @concurrent 以進行背景負載平衡,以及針對 MainActor 類型的隔離型協定(Isolated Conformances)。
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Swift 6.2 易用併發模式 (Approachable Concurrency)
|
|||
|
|
|
|||
|
|
這是採用 Swift 6.2 併發模型的實踐模式。在該模型中,程式碼預設在單線程運行,僅在顯式標註時才引入併發。這能消除常見的資料競爭 (Data-race) 錯誤,同時不犧牲效能。
|
|||
|
|
|
|||
|
|
## 何時啟用
|
|||
|
|
|
|||
|
|
- 將 Swift 5.x 或 6.0/6.1 專案遷移至 Swift 6.2。
|
|||
|
|
- 解決編譯器回報的資料競爭安全錯誤。
|
|||
|
|
- 設計基於 `@MainActor` 的應用程式架構。
|
|||
|
|
- 需要將消耗大量 CPU 的工作移至背景線程處理。
|
|||
|
|
- 在 MainActor 隔離類型上實作協定順應性 (Protocol Conformances)。
|
|||
|
|
|
|||
|
|
## 核心概念:預設單線程行為
|
|||
|
|
|
|||
|
|
在 Swift 6.1 之前的版本中,`async` 函式可能會被隱含地移至背景線程,導致即使是看似安全的程式碼也會觸發資料競爭。
|
|||
|
|
**Swift 6.2 修正了這一點**:非同步函式預設會保留在「調用者」所在的 Actor 上(通常是 MainActor)。
|
|||
|
|
|
|||
|
|
### 核心模式 1 — 隔離型協定 (Isolated Conformances)
|
|||
|
|
MainActor 類型現在可以安全地順應非隔離的協定:
|
|||
|
|
|
|||
|
|
```swift
|
|||
|
|
protocol Exportable {
|
|||
|
|
func export()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Swift 6.2:使用隔離性順應性,編譯器保證該協定內容僅在 MainActor 上執行
|
|||
|
|
extension StickerModel: @MainActor Exportable {
|
|||
|
|
func export() {
|
|||
|
|
photoProcessor.exportAsPNG()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 核心模式 2 — 顯式背景處理 `@concurrent`
|
|||
|
|
當你真正需要平行處理效能時,顯式使用 `@concurrent` 標記將任務移交給併發線程池:
|
|||
|
|
|
|||
|
|
```swift
|
|||
|
|
nonisolated final class PhotoProcessor {
|
|||
|
|
// 顯式將耗時作業移至背景
|
|||
|
|
@concurrent
|
|||
|
|
static func extractSubject(from data: Data) async -> Sticker { /* 處理邏輯 ... */ }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 調用者必須使用 await
|
|||
|
|
let sticker = await PhotoProcessor.extractSubject(from: data)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 遷移建議
|
|||
|
|
|
|||
|
|
1. **Xcode 設定**:在 Build Settings 的 Swift Compiler -> Concurrency 區段啟用相關功能。
|
|||
|
|
2. **預設使用 MainActor**:建議應用程式 Target 啟用「預設推斷 MainActor」模式,減少手動標記範本代碼。
|
|||
|
|
3. **優化熱點路徑**:先進行測速效能分析 (Profile),僅針對真正的效能瓶頸(如圖片處理、大型計算)才掛上 `@concurrent`。
|
|||
|
|
|
|||
|
|
## 實踐之最佳實踐
|
|||
|
|
|
|||
|
|
- **從 MainActor 開始**:優先撰寫單線程程式碼,優化留到最後。
|
|||
|
|
- **僅針對運算密集型工作使用 `@concurrent`**:如編碼、壓縮、複雜算法。
|
|||
|
|
- **相信編譯器**:如果編譯器報告資料競爭,則代表程式碼邏輯確實存在併發風險,請勿試圖使用 `nonisolated` 掩蓋問題。
|
|||
|
|
|
|||
|
|
## 應避免的反模式
|
|||
|
|
|
|||
|
|
- 對每一個 `async` 函式都標記 `@concurrent`(大多數情況下並不需要背景執行)。
|
|||
|
|
- 假設所有非同步程式碼都在背景執行(在 Swift 6.2 中,預設是留在原 Actor 執行的)。
|