swift 如何向等待的函数调用添加超时

bvpmtnay  于 2022-12-10  发布在  Swift
关注(0)|答案(2)|浏览(186)

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

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()不返回的情况下更加健壮。如果使用合并,我会使用timeout操作符。

e4yzc0pl

e4yzc0pl1#

我们可以创建一个Task,如果它在一段时间内没有完成,则再创建一个cancel。例如,并行启动两个任务:

// 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副本(如果还没有得话).

mwg9r5ms

mwg9r5ms2#

//您可以使用'try and catch'。等候try区块内的撷取数据。当撷取失败时,catch区块可以执行不同的陈述式。例如:

await getResource() 
    try {
        await fetchData();
    } catch(err){
        doSomethingElse();
    }
    // program continues

相关问题