Swift 并发机制的截止日期算法。
正如我之前在 Swift 论坛 上所述:在我看来,截止日期或超时是 Swift 并发系统中缺失的一部分。由于这个算法不容易实现正确,我决定开源我的实现。
该库附带两个自由函数,一个带有通用时钟,另一个使用 ContinuousClock
作为默认时钟。
public func deadline<C, R>(
until instant: C.Instant,
tolerance: C.Instant.Duration? = nil,
clock: C,
isolation: isolated (any Actor)? = #isolation,
operation: @Sendable () async throws -> R
) async throws -> R where C: Clock, R: Sendable { ... }
public func deadline<R>(
until instant: ContinuousClock.Instant,
tolerance: ContinuousClock.Instant.Duration? = nil,
isolation: isolated (any Actor)? = #isolation,
operation: @Sendable () async throws -> R
) async throws -> R where R: Sendable { ... }
此函数提供了一种机制,用于对缺乏原生截止日期支持的异步操作强制执行超时。它创建一个包含两个并发任务的 TaskGroup
:提供的操作和一个休眠任务。
参数
instant
: 操作完成的绝对截止日期。tolerance
: 截止日期的允许容差。clock
: 用于计时操作的时钟。isolation
: 传递给任务组的隔离。operation
: 要执行的异步操作。返回值:如果操作在截止日期之前完成,则返回操作的结果。
抛出:DeadlineExceededError
,如果操作未能在截止日期之前完成,以及操作或时钟抛出的错误。
注意
操作闭包必须支持协作取消。否则,截止日期将不会被遵守。
为了充分理解这一点,让我们说明此函数的 3 种结果
操作及时完成
let result = try await deadline(until: .now + .seconds(5)) {
// Simulate long running task
try await Task.sleep(for: .seconds(1))
return "success"
}
正如您所预料的那样,结果将是“success”。当您的操作及时失败时,情况也是如此
let result = try await deadline(until: .now + .seconds(5)) {
// Simulate long running task
try await Task.sleep(for: .seconds(1))
throw CustomError()
}
这将抛出 CustomError
。
操作未能在规定时间内完成
let result = try await deadline(until: .now + .seconds(1)) {
// Simulate even longer running task
try await Task.sleep(for: .seconds(5))
return "success"
}
这将抛出 DeadlineExceededError
,因为操作将无法在规定时间内完成。
父任务被取消
let task = Task {
do {
try await deadline(until: .now + .seconds(5)) {
try await URLSession.shared.data(from: url)
}
} catch {
print(error)
}
}
task.cancel()
打印保证会打印 URLError(.cancelled)
。
clock
参数,其默认表达式为 ContinuousClock
。 @isolated(any)
以支持同步任务入队。