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 的,例如结构体和枚举。

广告