文章序列:
Task
在swift中創(chuàng)建Task很簡單废恋,使用Task類的構(gòu)造函數(shù)就可以
let basicTask = Task {
let result = await someAsync()
return result
}
Task可以返回執(zhí)行結(jié)果问窃,當(dāng)任務(wù)執(zhí)行出錯時也可以拋出異常
let basicTask = Task {
// .. perform some work
throw ExampleError.somethingIsWrong
}
do {
print(try await basicTask.value)
} catch {
print("Basic task failed with error: \(error)")
}
我們看一下Task的定義會發(fā)現(xiàn)創(chuàng)建Task實際上是通過構(gòu)造一個閉包來初始化了一個Task實例烁试,在這個閉包里可以執(zhí)行任意異步函數(shù)帽揪。
public init(
priority: _Concurrency.TaskPriority? = nil,
operation: @escaping () async -> Success)
public init(
priority: _Concurrency.TaskPriority? = nil,
operation: @escaping () async throws -> Success)
除了 init
構(gòu)造 Task 之外,Task 還提供 detach
函數(shù)來創(chuàng)建一個不一樣的 Task:
public static func detached(
priority: _Concurrency.TaskPriority? = nil,
operation: @escaping () async -> Success
) -> _Concurrency.Task<Success, Failure>
public static func detached(
priority: _Concurrency.TaskPriority? = nil,
operation: @escaping () async throws -> Success
) -> _Concurrency.Task<Success, Failure>
Task.detached
創(chuàng)建的task和 Task.init
創(chuàng)建的Task有所不同的是 Task.detached
創(chuàng)建的task獨立運行于當(dāng)前的Actor,這個Actor的概念我們以后會講到阱佛,你可以先簡單理解為線程執(zhí)行的隔離上下文(保障線程安全用的)帖汞。
Task的取消很簡單,調(diào)用task的cancel
方法就行
let imageTask = Task { () -> UIImage? in
let imageURL = URL(string: "https://source.unsplash.com/random")!
let (imageData, _) = try await URLSession.shared.data(from: imageURL)
return UIImage(data: imageData)
}
// Cancel the image request right away:
imageTask.cancel()
非結(jié)構(gòu)化任務(wù)和結(jié)構(gòu)化任務(wù)
通過Task創(chuàng)建構(gòu)造的任務(wù)凑术,也被稱為非結(jié)構(gòu)化的并發(fā)任務(wù)。與之對應(yīng)的是添加到TaskGroup的任務(wù)被稱為結(jié)構(gòu)化Task所意。
TaskGroup可以通過add方法將一系列Task添加到一個組里面淮逊,TaskGroup會等待所有task都返回后才進行返回。
let images = await withTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
let photoURLs = await listPhotoURLs(inGallery: "Amsterdam Holiday")
for photoURL in photoURLs {
taskGroup.addTask { await downloadPhoto(url: photoURL) }
}
var images = [UIImage]()
for await result in taskGroup {
images.append(result)
}
return images
}
TaskGroup 也遵循AsyncSequence
協(xié)議扶踊,可以使用reduce
方式獲取結(jié)果
let images = try await withThrowingTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
let photoURLs = try await listPhotoURLs(inGallery: "Amsterdam Holiday")
for photoURL in photoURLs {
taskGroup.addTask { try await downloadPhoto(url: photoURL) }
}
return try await taskGroup.reduce(into: [UIImage]()) { partialResult, image in
partialResult.append(image)
}
}
上述例子中的TaskGroup會等待每個任務(wù)都執(zhí)行完成泄鹏,如果遇到一個任務(wù)失敗想要提前返回,也可以提前return或者針對ThrowingTaskGroup拋出異常
let images = try await withThrowingTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
let photoURLs = try await listPhotoURLs(inGallery: "Amsterdam Holiday")
for photoURL in photoURLs {
taskGroup.addTask { try await downloadPhoto(url: photoURL) }
}
var images = [UIImage]()
/// Note the use of `next()`:
while let downloadImage = try await taskGroup.next() {
images.append(downloadImage)
}
return images
}
這里調(diào)用next
方法在結(jié)果返回為nil時結(jié)束了循環(huán)秧耗,提前return之前接收的結(jié)果集备籽。
如果要對TaskGroup進行取消,可以調(diào)用cancelAll()
對添加到組里的每個Task進行取消操作分井。需要注意的是TaskGroup調(diào)用取消操作后车猬,后續(xù)添加的task不會自動開始而是自動取消,如果還需要任務(wù)進行可以通過addTaskUnlessCancelled()來讓任務(wù)執(zhí)行尺锚。