文章序列:
Task
在swift中创建Task很简单,使用Task类的构造函数就可以
let basicTask = Task {
let result = await someAsync()
return result
}
Task可以返回执行结果,当任务执行出错时也可以抛出异常
let basicTask = Task {
// .. perform some work
throw ExampleError.somethingIsWrong
}
do {
print(try await basicTask.value)
} catch {
print("Basic task failed with error: \(error)")
}
我们看一下Task的定义会发现创建Task实际上是通过构造一个闭包来初始化了一个Task实例,在这个闭包里可以执行任意异步函数。
public init(
priority: _Concurrency.TaskPriority? = nil,
operation: @escaping () async -> Success)
public init(
priority: _Concurrency.TaskPriority? = nil,
operation: @escaping () async throws -> Success)
除了 init
构造 Task 之外,Task 还提供 detach
函数来创建一个不一样的 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
创建的task和 Task.init
创建的Task有所不同的是 Task.detached
创建的task独立运行于当前的Actor,这个Actor的概念我们以后会讲到,你可以先简单理解为线程执行的隔离上下文(保障线程安全用的)。
Task的取消很简单,调用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()
非结构化任务和结构化任务
通过Task创建构造的任务,也被称为非结构化的并发任务。与之对应的是添加到TaskGroup的任务被称为结构化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
协议,可以使用reduce
方式获取结果
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会等待每个任务都执行完成,如果遇到一个任务失败想要提前返回,也可以提前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
}
这里调用next
方法在结果返回为nil时结束了循环,提前return之前接收的结果集。
如果要对TaskGroup进行取消,可以调用cancelAll()
对添加到组里的每个Task进行取消操作。需要注意的是TaskGroup调用取消操作后,后续添加的task不会自动开始而是自动取消,如果还需要任务进行可以通过addTaskUnlessCancelled()来让任务执行。
网友评论