Task优先级与取消
在Swift并发中,Task不仅是一个异步任务的执行容器,还提供了优先级控制和取消功能,让开发者能够更精细地管理任务的执行顺序和生命周期。前一节介绍了Task的基本创建与管理,本节将聚焦于Task的优先级设置和取消操作,讲解其工作原理、使用场景及最佳实践。通过这些知识,你将能优化任务调度并处理用户中断需求。
Task优先级
Swift允许通过priority参数为Task指定执行优先级,影响其在底层GCD线程池中的调度顺序。优先级设置并非强制执行,而是系统根据资源可用性和其他任务的竞争进行调整。
优先级选项
TaskPriority枚举提供了以下常见值:
- .userInitiated:用户触发的紧急任务(如按钮点击),高优先级。
- .high:重要但非交互的任务。
- .default:默认优先级,适用于大多数情况。
- .utility:中等优先级,适合次要操作。
- .background:最低优先级,用于后台任务(如日志同步)。
示例:
func processData() async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000)
return "处理完成"
}
Task(priority: .userInitiated) {
let result = await processData()
print("高优先级:\(result) - \(Task.currentPriority.rawValue)")
}
Task(priority: .background) {
let result = await processData()
print("低优先级:\(result) - \(Task.currentPriority.rawValue)")
}
输出可能为:
高优先级:处理完成 - 25
低优先级:处理完成 - 9
Task.currentPriority:检查当前任务的优先级(数值越高,优先级越高)。
优先级继承
子任务会继承父任务的优先级,除非显式指定:
Task(priority: .high) {
print("父任务优先级:\(Task.currentPriority.rawValue)")
Task {
print("子任务继承优先级:\(Task.currentPriority.rawValue)")
}
Task(priority: .background) {
print("子任务覆盖优先级:\(Task.currentPriority.rawValue)")
}
}
输出:
父任务优先级:21
子任务继承优先级:21
子任务覆盖优先级:9
- 未指定优先级的子任务继承父级。
- 显式指定会覆盖继承。
使用场景
- 用户交互:
.userInitiated确保快速响应。 - 批量处理:
.utility或.background避免抢占主线程。 - 混合任务:不同优先级区分重要性。
Task取消
Task支持取消操作,通过cancel()方法通知任务停止。取消是一种协作机制,任务需主动检查并响应。
基本取消
调用cancel()并检查isCancelled:
let task = Task {
for i in 1...5 {
try? await Task.sleep(nanoseconds: 500_000_000)
guard !Task.isCancelled else {
print("任务已取消")
return
}
print("进度:\(i)")
}
print("任务完成")
}
Task {
try? await Task.sleep(nanoseconds: 1_500_000_000)
task.cancel()
}
输出:
进度:1
进度:2
进度:3
任务已取消
isCancelled:布尔值,表示任务是否被取消。- 开发者需在逻辑中检查并退出。
取消传播
父任务取消时,子任务自动收到通知:
let parentTask = Task {
Task {
try? await Task.sleep(nanoseconds: 2_000_000_000)
guard !Task.isCancelled else {
print("子任务取消")
return
}
print("子任务完成")
}
try? await Task.sleep(nanoseconds: 1_000_000_000)
print("父任务运行")
}
Task {
try? await Task.sleep(nanoseconds: 500_000_000)
parentTask.cancel()
}
输出:
父任务运行
子任务取消
- 父任务取消后,子任务的
isCancelled变为true。 - 需显式检查,未检查的任务继续运行。
抛出取消错误
Swift提供CancellationError,可在检查时抛出:
let cancellableTask = Task {
for i in 1...5 {
try await Task.sleep(nanoseconds: 500_000_000)
try Task.checkCancellation() // 抛出CancellationError
print("进度:\(i)")
}
}
Task {
try? await Task.sleep(nanoseconds: 1_000_000_000)
cancellableTask.cancel()
do {
try await cancellableTask.value
} catch {
print("任务取消:\(error)")
}
}
输出:
进度:1
任务取消:CancellationError()
checkCancellation():若已取消,抛出错误,简化逻辑。
实际应用
1. 用户中断
响应用户取消操作:
class DownloadViewController: UIViewController {
var downloadTask: Task<Void, Never>?
@IBAction func startDownload(_ sender: UIButton) {
downloadTask = Task {
for i in 1...10 {
try? await Task.sleep(nanoseconds: 1_000_000_000)
guard !Task.isCancelled else { return }
await MainActor.run { progressLabel.text = "进度:\(i)0%" }
}
await MainActor.run { progressLabel.text = "完成" }
}
}
@IBAction func cancelDownload(_ sender: UIButton) {
downloadTask?.cancel()
progressLabel.text = "已取消"
}
}
- 高优先级任务响应用户点击。
2. 优先级调度
优化多任务执行:
Task(priority: .userInitiated) {
let data = await fetchCriticalData()
print("关键数据:\(data)")
}
Task(priority: .background) {
let log = await syncLogs()
print("日志同步:\(log)")
}
- 关键任务优先执行。
最佳实践
合理设置优先级
避免所有任务都用.high,会导致优先级失效。及时检查取消
在循环或耗时操作中定期检查isCancelled。清理资源
取消后释放占用资源(如网络连接)。日志记录
记录取消事件,便于调试:if Task.isCancelled { print("任务\(task.id)取消") }
小结
Task的优先级和取消功能为异步任务管理提供了灵活性。优先级控制任务调度顺序,取消机制响应中断需求。本节通过示例展示了其用法和应用场景,强调了协作取消的重要性。掌握这些技巧,你将能优化任务执行并处理动态需求。下一节将探讨结构化并发,进一步提升你的并发设计能力。
内容说明
- 结构:从优先级到取消,再到应用和实践,最后总结。
- 代码:包含优先级、取消和UI示例,突出实用性。
- 语气:深入且实践导向,适合技术书籍深入章节。
- 衔接:承接前节(
Task基础),预告后续(结构化并发)。
