swift - 如何为等待函数调用添加超时

为等待函数添加超时的最佳方法是什么?

Example:

/// lets pretend this is in a library that I'm using and I can't mess with the guts of this thing
func fetchSomething() async -> Thing? {
    // fetches something
}

// if fetchSomething() never returns then doSomethingElse() is never ran. Is there anyway to add a timeout to this system?
let thing = await fetchSomething()
doSomethingElse()

我想让系统在 fetchSomething() 永远不会返回的情况下更加健壮。如果这是使用组合,我会使用超时运算符。

最佳答案

可以创建一个任务,然后如果它在特定时间段内没有完成则取消它。例如,并行启动两个任务:

// cancel the fetch after 2 seconds

func fetchSomethingWithTimeout() async throws -> Thing {
    let fetchTask = Task {
        try await fetchSomething()
    }

    let timeoutTask = Task {
        try await Task.sleep(nanoseconds: 2 * NSEC_PER_SEC)
        fetchTask.cancel()
    }

    let result = try await fetchTask.value
    timeoutTask.cancel()

    return result
}

// here is a random mockup that will take between 1 and 3 seconds to finish

func fetchSomething() async throws -> Thing {
    let duration: TimeInterval = .random(in: 1...3)

    try await Task.sleep(nanoseconds: UInt64(TimeInterval(NSEC_PER_SEC) * duration))

    return Thing()
}

如果 fetchTask 先完成,它将到达 timeoutTask.cancel 并停止它。如果 timeoutTask 先完成,它将取消 fetchTask

显然,这取决于 fetchTask 的实现。它不仅应该检测取消,还应该在取消时抛出错误(可能是 CancellationError )。如果没有有关 fetchTask 实现的详细信息,我们无法进一步发表评论。

例如,在上面的例子中,我不会返回一个可选的Thing?,而是返回Thing,但让它throw如果取消则出错。


我犹豫要不要提它,但是虽然上面假设 fetchSomething 表现良好(即可取消),但即使它不工作(即运行doSomethingElse 在一些合理的时间表中,即使 fetchSomething “永远不会返回”)。

但这本质上是一种不稳定的情况,因为 fetchSomething 使用的资源在它完成之前无法恢复。 Swift 不提供抢先取消,因此虽然我们可以轻松解决确保 doSomethingElse 最终运行的战术问题,但如果 fetchSomething 可能永远不会在某个合理的时间表内完成,您有更深层次的问题。

你真的应该找到一个可取消的 fetchSomething 版本,如果它还没有的话。

https://stackoverflow.com/questions/74710155/

相关文章:

python - Pandas dataframe,连续查找所选列中的最大值,并根据该值查找另一列的

python - ModuleNotFoundError 即使模块被识别

node.js - 为什么当我使用 "waitForSelector"时 Puppeeteer 导致

haskell - 如何测试自定义 StateT 的 Monad 实例?

javascript - 是的,当 .required() 为 false 时,会继续在同一个属性上

windows-installer - 在 Windows 的添加/删除程序中显示正确的大小

c++ - Clang 静态链接 libc++

qt - Qt中,对于上下文菜单项,如何隐藏图标的空间

typescript - 如何在保持默认行为的同时扩展 tsconfig 中的类型

laravel - 生产模式编译报错 "is not a function"Vue Laravel