Swift 两种方式实现 async/await 并发模型中任务超时(timeout)的处理
Posted 大熊猫侯佩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 两种方式实现 async/await 并发模型中任务超时(timeout)的处理相关的知识,希望对你有一定的参考价值。
文章目录
1. 概览
从 Swift 5.5 开始,Apple 引入了新的 async/await 并发模型,我们可以利用它很方便的开发结构化并发代码。
在使用新的并发模型时,一个常见的需求就是任务超时的处理。
我们希望当耗时任务的执行在到达指定时间后自动取消,以免影响用户体验。
在本篇博文中,我们将用两种方法来实现新并发模型中 Task 执行的超时处理。
废话少叙,Let’s Go!!!😉
2. Task 超时处理实现之思路
在 Swift 新 async/await 并发模型中,每个 Task 都会并发执行。所以,要想实现任务超时处理我们只需要同时执行两个任务:
- 第一个是需要完成的任务;
- 第二个是超时监控任务,用它来监听第一个任务是否已超时,如果是则果断取消它;
有的小伙伴可能觉得实现监控任务有点棘手,其实,这超乎意料的简单!
3. 第一种实现
我们只需保存执行的 Task 对象,然后在超时发生时,在第二个超时监控任务中将其取消即可,代码如下:
struct TimedOutError: Error, Equatable
func execute<R>(timeout: TimeInterval, task: @escaping () async throws -> R) async throws -> R
let task = Task
try await task()
Task
try? await Task.sleep(until: .now + .seconds(timeout), clock: .continuous)
task.cancel()
do
return try await task.value
catch
// 如果任务被取消,则我们知道任务超时了
if task.isCancelled
throw TimedOutError()
throw error
正如之前的实现思路,我们依次创建了两个任务:第一个是需要完成的任务,第二个则是超时监控任务;在第二个任务中,一旦超时到达,则取消第一个任务。
Task
do
let r = try await execute(timeout: 3.0)
// 任务会触发超时,将被取消!
try await Task.sleep(until: .now + .seconds(3.1), clock: .continuous)
return 11
print("结果是 \\(r)")
catch
print("ERR: \\(error.localizedDescription)")
不过,这样有两个小问题:
- 如果第一个任务在超时前完成,超时监控任务在超时后仍会尝试取消它;
- 当任务执行出现异常时,我们需要判断任务是否被取消,然后再抛出 TimedOutError 错误;
虽然,这并不影响整个 execute() 方法的逻辑,但如果小伙伴们是强迫症患者,我们还有第二种方法可以选择。
4. 第二种实现
第二种方法和前者类似,不过这里我们利用了新并发模型中任务组(TaskGroup)的特点:其中所有子任务都会并发执行,而且我们可以取消所有子任务。
func execute2<R>(timeout: TimeInterval, task: @escaping () async throws -> R) async throws -> R
try await withThrowingTaskGroup(of: R.self) group in
group.addTask
try await task()
group.addTask
try await Task.sleep(until: .now + .seconds(timeout), clock: .continuous)
throw TimedOutError()
let result = try await group.next()!
// 一旦我们取消所有子任务,则超时监控任务不会在正常任务未超时还抛出异常
group.cancelAll()
return result
如上代码所示,用 TaskGroup 来实现任务超时逻辑更加清晰,而且避免了第一种方法中的两个问题。
更多 Task 任务超时的讨论请参考下面的链接:
Running an async task with a timeout
5. 总结
在本篇博文中,我们用两种方法实现了 Swift 新 async/await 并发模型中任务超时的处理,任君选择。
感谢观赏,再会!😎
以上是关于Swift 两种方式实现 async/await 并发模型中任务超时(timeout)的处理的主要内容,如果未能解决你的问题,请参考以下文章
Swift 两种方式实现 async/await 并发模型中任务超时(timeout)的取消
Vue 两种处理异步的方式 Promise Async/Await
Swift新async/await并发模型中子任务取消不能被其它子任务感知的原因及解决