Swift Concurrency(并发)学习
Swift 的并发模型是基于和的一套现代化的异步编程工具。以下是相关语法规则总结asyncawait。
·
Swift 的并发模型是基于 异步任务 和 任务调度 的一套现代化的异步编程工具。以下是相关语法规则总结
1. 异步函数(async
)与 await
async
用于声明一个异步函数,表示函数可能会执行耗时任务,例如网络请求、文件读写等。- 在调用异步函数时,使用
await
关键字等待函数返回结果。
示例
func fetchUserID(from server: String) async -> Int {
if server == "primary" {
return 97
}
return 501
}
async
声明: 表示fetchUserID
是异步函数。- 返回值类型:
async
函数支持返回值,格式为async -> ReturnType
。 - 在异步函数内部,可以通过一些耗时操作(如网络请求)返回结果。
调用异步函数
func fetchUsername(from server: String) async -> String {
let userID = await fetchUserID(from: server) // 用 await 调用异步函数
if userID == 501 {
return "John Appleseed"
}
return "Guest"
}
await
关键字: 调用异步函数时需要等待其执行完成。- 通过
await
,程序会暂停当前任务,直到异步函数返回结果。
2. 使用 async let
实现并发任务
- 如果多个异步任务之间互不依赖,可以用
async let
并发地执行它们。 async let
启动的任务是并发运行的,但当你使用返回值时需要用await
。
示例
func connectUser(to server: String) async {
async let userID = fetchUserID(from: server) // 异步获取 userID
async let username = fetchUsername(from: server) // 异步获取 username
// 等待两个任务完成,合并结果
let greeting = await "Hello \(username), user ID \(userID)"
print(greeting)
}
async let
: 声明异步任务,让它们同时运行。await
: 当需要用返回值时才等待任务完成。- 并发执行可以显著提升性能,尤其在多个任务需要执行时。
3. 使用 Task
从同步代码中调用异步函数
- 如果当前代码是同步上下文(比如普通函数或全局代码),可以用
Task
调用异步函数。
示例
Task {
await connectUser(to: "primary")
}
// 输出:Hello Guest, user ID 97
Task
: 一个封装异步代码的上下文,它不会阻塞当前线程。- 执行顺序:
Task
会在后台运行,不会阻塞主线程。
4. 使用 TaskGroup
进行任务分组
TaskGroup
是 Swift 的一种工具,用于管理一组并发任务。- 使用任务分组时,可以动态添加任务并收集任务结果。
示例
let userIDs = await withTaskGroup(of: Int.self) { group in
for server in ["primary", "secondary", "development"] {
group.addTask {
return await fetchUserID(from: server)
}
}
var results: [Int] = []
for await result in group {
results.append(result)
}
return results
}
withTaskGroup
: 创建一个任务组。group.addTask
: 动态向任务组中添加任务。for await
: 异步地收集任务结果。
输出:
假设 fetchUserID
返回的结果为 [97, 501, 97]
,最终的 userIDs
为 [97, 501, 97]
。
5. Actor
- Actor 是 Swift 提供的一种结构,保证并发访问的安全性。
- 与类(
class
)类似,actor
也可以包含属性和方法。 - 区别:
- Actor 是并发安全的:它会序列化对其属性的访问,避免数据竞争。
- 在调用 Actor 的方法或访问属性时,必须使用
await
。
示例
actor ServerConnection {
var server: String = "primary"
private var activeUsers: [Int] = []
func connect() async -> Int {
let userID = await fetchUserID(from: server)
activeUsers.append(userID)
return userID
}
}
let server = ServerConnection()
let userID = await server.connect()
- Actor 的特点:
ServerConnection
中的server
和activeUsers
属性只能通过 Actor 内部的方法访问。- 调用
connect
方法时必须用await
,因为它可能涉及异步操作。
6. 重要语法总结
async
和await
:- 用于声明和调用异步函数。
- 异步函数可以暂停当前任务,等待其他任务完成。
async let
:- 并发地启动多个异步任务,但只在需要时等待结果。
Task
:- 用于从同步代码中调用异步函数。
TaskGroup
:- 管理多个并发任务,并收集它们的结果。
- Actor:
- 确保对共享状态的并发访问是安全的。
7. 拓展知识
Swift 的并发功能建立在底层 GCD(Grand Central Dispatch) 和 Swift Concurrency Runtime 之上,以下是一些拓展知识:
7.1 串行队列 vs 并发队列
- 串行队列: 一个任务完成后才开始下一个任务。
- 并发队列: 多个任务同时运行,但完成顺序不保证。
7.2 异步序列和迭代
Swift 支持 异步序列(AsyncSequence
),可以异步地遍历序列:
struct Counter: AsyncSequence {
typealias Element = Int
let end: Int
func makeAsyncIterator() -> AsyncIterator {
return AsyncIterator(end: end)
}
struct AsyncIterator: AsyncIteratorProtocol {
let end: Int
var current = 0
mutating func next() async -> Int? {
current += 1
return current <= end ? current : nil
}
}
}
for await number in Counter(end: 5) {
print(number)
}
// 输出:1 2 3 4 5
更多推荐
已为社区贡献1条内容
所有评论(0)