如何打断Thread.sleep。备择方案?

How to interrupt Thread.sleep. Alternatives?

我已经在 OperationQueue 上实现了一个操作。

override func main() {
    super.main()
    if isCancelled {
        return
    }
    if member.memberType == .timed {
        triggerRestEvent(duration: member.restDuration)
    }
    if isCancelled {
        triggerEndEvent()
    }
}

triggerRestEvent函数实际上是在调用Thread.sleep。一旦睡眠结束,我们就会检查 isCancelled.

有没有办法在 isCancelled 开启时中断 Thread.sleep

备选 - RunLoop

RunLoop 文档建议在函数 run 周围使用 while 循环,并在 while 循环中使用自定义条件。但是我如何设置一个计时器来切换 while 循环执行呢?显然,为了这个目的,以这种方式使用 while 循环,现在是一种反模式吗?

Thread.sleep 是 non-cancelable 并阻塞线程。在 RunLoop 上旋转是低效的。话虽如此,还有一些选择:

  1. 现在,为了管理异步任务之间的依赖关系,我们会达到 Swift 并发的 Task 而不是 Operation。在 Swift 并发中,我们有 Task.sleep,与 Thread.sleep 不同,它是可取消的,不会阻塞线程。

  2. 如果您想保持 OperationQueue 模式,您可以使用异步自定义 Operation 子类(可能是 [=33= 中显示的 AsynchronousOperation ]), 然后你会使用一个计时器。您可以使用 DispatchSourceTimerTimerasyncAfter 以及可取消的 DispatchWorkItem。您选择哪个并不重要。关键是确保 cancel 实现使 Timer 无效或取消 DispatchWorkItemDispatchSourceTimer,例如:

    class OneSecondOperation: AsynchronousOperation {
        weak var timer: Timer?
    
        override func main() {
            DispatchQueue.main.async {
                self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in
                    self?.finish()
                }
            }
        }
    
        override func cancel() {
            super.cancel()
            timer?.invalidate()
            finish()
        }
    }
    

    请注意,您定期检查 isCancelled 的模式仅适用于存在现有循环的情况。例如,如果您正在进行一些迭代计算,那么这是一个非常合理的模式。但是如果你只是在等待,引入一个循环来检查 isCancelled 的想法是低效的。相反,设置一个计时器并实现取消该计时器的 cancel 方法,如上所示。

无论哪种方式,您都希望实现不阻塞线程并且可以取消。对于 Operation 子类,您必须自己实现它。使用 Swift 并发,您可以免费获得它。