Swift 函数的超时

问题描述 投票:0回答:1

我完成了一个 Swift 库的编写,我需要在一些示例上测试它的性能。

我正在 Swift 中创建一个脚本,将一些数据放入文件中,使用我的库执行它们,然后返回执行时间等结果。

从这些文件中提取的不同示例列表中,其中一些可能需要数小时才能执行,而另一些则只需几秒钟。我不希望得到所有示例的答案,我只想要那些在“x”秒内完成的示例的结果。因此,如果我的函数调用时间超过“x”秒,我想引入超时。它应该停止当前执行并转到下一个。

我寻找解决方案,其中一些使用异步/等待或调度队列,但没有任何对我有用。以下是我尝试过的解决方案之一:

func evalWithTimer(key: String, somethingToExecute: SomethingToExecute) -> SVS? {

  var res: SVS? = nil
  // Create a semaphore
  let semaphore = DispatchSemaphore(value: 0)

  // Define the time limit in seconds
  let timeLimit: DispatchTime = .now() + 1 // 1 seconds

  // Define the task you want to run (replace this with your actual task)
  let task = {
    res = somethingToExecute.eval()
    semaphore.signal() // Signal that the task is done
  }

  // Execute the task asynchronously
  DispatchQueue.global().async(execute: task)

  // Wait for the task to complete or time out
  let result = semaphore.wait(timeout: timeLimit)

  if result == .timedOut {
    // Task did not complete within the time limit, you can cancel it if needed
    print("Task evaluation timed out and was canceled")
    return res
  } else {
    // Task completed within the time limit
    print("Task evaluation completed within the time limit")
    return res
  }

}

我的函数 evalWithTimer 被调用以获取 SomethingToExecute 中的不同值。当我对其调用

eval()
时,可能会花费超过 1 秒的时间,如果这是真的,则应该停止。在当前版本中,它不起作用,因为任务
eval()
未正确取消。至少这是我的假设。即使在超时为真时添加
task.cancel()
也不会改变任何东西。

我发现的唯一解决方案添加了异步机制,这是可以理解的。我正在寻找这个问题的解决方案,无论是否基于上面的代码。

请注意,

somethingToExecute.eval()
不是异步的。

swift asynchronous async-await timeout
1个回答
0
投票

阻止事情发生应该是合作的努力。

eval
应检查自身是否被取消,如果是,则停止正在执行的任何操作。

例如,使用 Swift Concurrency,

eval
可以在执行过程中的适当位置检查
Task.isCancelled
,或者如果是
throws
,您可以改为
try Task.checkCancellation()

假设

eval
是一个长时间运行的循环,你可以在每次迭代中进行检查:

while something {
    if Task.isCancelled { return nil /* or however you'd like to stop it*/ }
    // or in a throwing function:
    // try Task.checkCancellation()

    // do work
}

然后,您可以执行两个任务,一个运行

eval
,另一个测量 1 秒,然后取消第一个任务。

func evalWithTimer(key: String, somethingToExecute: SomethingToExecute) async throws -> SVS? {
    let evalTask = Task {
        somethingToExecute.eval()
        // if eval is throwing,
        // try somethingToExecute.eval()
    }
        
    let timeoutTask = Task {
        try await Task.sleep(for: .seconds(1))
        evalTask.cancel()
        // here you know the timeout is exceeded
    }
        
    // if eval is throwing, "try" await, a CancellationError would be thrown if the timeout exceeds
    let result = await evalTask.value
    timeoutTask.cancel()
    return result
}
© www.soinside.com 2019 - 2024. All rights reserved.