Swift 併發



併發允許 Swift 程式同時執行多個任務或操作。或者我們可以說它允許我們以結構化的方式編寫非同步和並行程式碼。我們可以暫停和恢復非同步程式碼。併發將提高應用程式的響應速度和效能。

非同步函式

在 Swift 中,非同步函式或方法是一種特殊的函式或方法,可以執行非阻塞和非同步操作。此類函式可以在執行過程中暫停,也可以暫停以等待某些事件。此外,我們還可以標記想要暫停函式執行的位置。

要建立一個非同步函式或方法,我們必須在引數列表之後和返回箭頭之前,在宣告部分使用 async 關鍵字。

語法

以下是非同步函式的語法:

func functionName(parameter) async -> returnType{
   // statement
}

要暫停非同步函式或方法的執行,直到等待的非同步操作完成,我們必須在呼叫前面使用 await 關鍵字。它使併發程式碼更容易閱讀。

以下是暫停非同步函式執行的語法:

await functionName(parameter)

非同步函式或方法也可以丟擲錯誤,我們可以使用 try 和 catch 塊來處理該錯誤。

以下是非同步函式處理錯誤的語法:

func functionName() async throws -> Data {
   // asynchronous code that may throw an error
}

do {
   let data = try await functionName()
   // process data
} catch {
   // handle error
}

我們還可以使用在定義常量時在 let 前面使用 async 關鍵字,然後在使用常量時編寫 await 關鍵字來並行呼叫非同步函式。

以下是並行呼叫非同步函式的語法:

// Calling asynchronous function in parallel
async let result1 = functionName1(parameter)
async let result2 = functionName2(parameter)

// Suspend execution
let suspendExecution = await[result1, result2]

示例

Swift 非同步函式程式。

// Asynchronous function
func randomFunc() async -> Int {
   Int.random(in: 10...40)
}

let result = await randomFunc()
print("Random Number:", result)

輸出

它將產生以下輸出:

Random Number: 13

任務和任務組

在 Swift 中,任務和任務組是幫助我們以結構化方式處理非同步程式碼的主要概念。任務是可以併發執行的工作單元。所有執行的非同步程式碼都是任務的一部分。通常,一個任務一次只能執行一個操作,但是當我們建立多個任務時,Swift 將安排它們同時執行。

而任務組用於管理任務集合並集體對其執行操作。這裡的任務按層次結構排列,這意味著給定組中的每個任務都有父任務和子任務,這種關係很重要,因為:

  • 在處理父任務時,不能忘記等待其任務完成。

  • 如果將子任務的優先順序設定為高,則父任務的優先順序將自動設定為高。

  • 如果父任務被取消,則子任務也將被取消。

  • 任務的區域性值可以輕鬆傳播到子任務。

任務取消

我們可以取消任務的執行。或者,我們可以在任務完成之前終止正在進行的任務。這在各種情況下都很有幫助,例如清理資源和停止長時間執行的操作。我們可以使用 Swift 提供的 cancel() 方法來取消任務。

示例

建立和取消任務的 Swift 程式。

import Foundation

class MyTaskManager {
   private var task: DispatchWorkItem?

   func createTask() {
    
      // Create a DispatchWorkItem
      task = DispatchWorkItem {
        
         for i in 1...5 {
            if self.task?.isCancelled ?? false {
               print("Task cancelled")
               return
            }
            print("Running task - \(i)")
         }
         print("Task completed successfully")
      }

      // Execute the task on a background queue
      DispatchQueue.global().async(execute: task!)
   }

   func cancelTask() {
    
      // Cancelling the task 
      task?.cancel()
   }
}

let obj = MyTaskManager()

// Create and run the task
obj.createTask()

// Wait for a while 
sleep(2)

// Cancel the task
obj.cancelTask()
輸出

它將產生以下輸出:

Running task - 1
Running task - 2
Running task - 3
Running task - 4
Running task - 5
Task completed successfully

Actor

眾所周知,任務用於將我們的程式分解成隔離的或併發的部分,這使得它們可以安全地同時執行。為了在這些任務之間新增一些資訊,Swift 提供了 Actor。Actor 是引用型別,它一次只允許一個任務訪問其可變狀態。這使得程式碼可以在多個任務中安全執行,並且可以輕鬆地與 Actor 的同一例項進行互動。在 Actor 中,如果外部程式碼嘗試直接訪問屬性,我們將收到錯誤。

我們可以使用 actor 關鍵字宣告一個 actor。此外,我們還可以像類和結構體一樣建立 Actor 的例項,以訪問 Actor 的屬性和方法。要暫停 Actor 的執行,我們可以使用 await 關鍵字。

語法

以下是並行呼叫非同步函式的語法:

// Calling asynchronous function in parallel
async let result1 = functionName1(parameter)
async let result2 = functionName2(parameter)

// Suspend execution
let suspendExecution = await[result1, result2]

示例

演示如何建立和使用 Actor 的 Swift 程式。

// Creating actor
actor MyCounter {

   private var num = 0

   func incrementValue() {
      num += 1
   }

   func getValue() -> Int {
      return num
   }
}
 
// Creating instance of actor
let obj = MyCounter() 

// Accessing actor methods
await obj.incrementValue()
let value = await obj.getValue()
print("Value: \(value)")

輸出

它將產生以下輸出:

Value: 1

Sendable 型別

眾所周知,任務和 Actor 可以將程式劃分為併發執行的程式碼片段。在任務或 Actor 例項內部,程式包含可變狀態(例如變數和屬性),它們也被稱為併發域。現在,某些資料不支援併發域,因此 Swift 提供了一種 Sendable 型別來在不同的併發域之間共享資料。

我們可以透過宣告符合 Sendable 協議來建立一個 Sendable 型別。它沒有任何程式碼要求,但有語義要求。通常,型別有三種方法可以是 Sendable 的:

  • 該型別必須具有值型別,其可變狀態由其他 Sendable 資料建立。

  • 該型別沒有任何可變狀態,其可變狀態由其他 Sendable 資料建立。

  • 確保其可變狀態安全的型別。

Swift 中某些型別始終是 Sendable 的,例如結構體和列舉。

廣告