DispatchSourceTimer,Timer和asyncAfter之间的区别?

J. *_*Doe 21 timer grand-central-dispatch swift

我正在努力了解DispatchSourceTimerTimerasyncAfter之间的主要区别(在我的情况下,该任务需要每X秒运行一次,尽管了解计时器的区别可能对有用)(或者是否有另一个(更有效)中除了列出的计时器外,还可以在Swift中使用调度机制?)。

A Timer需要在其开始的当前队列上有一个活动的运行循环。一个DispatchSourceTimer不需要。A Timer可防止CPU进入空闲状态。这是否也适用于DispatchSourceTimer/ asyncAfter

在什么情况下,a Timer优于DispatchSourceTimer/ asyncAfter?当然,它们之间的区别是什么?

我想在私人队列中的应用程序中每15秒安排一次工作。这意味着我必须使用,DispatchSourceTimer因为我在不是主线程的队列中(或将runloop添加到队列中并使用Timer)。但是,即使Timer最初使用a,我也看不到任何好处。也许我可以使用另一个操作在私有队列上每X秒执行一次调度工作,该工作比a更为有效DispatchSourceTimer,但是我没有遇到更好的解决方案。

是一个DispatchSourceTimer比一个更有效Timer?还是应该继续使用的自调用方法asyncAfter

这是创建计时器的代码。

异步之后

DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(2)) {
    // Code
}
Run Code Online (Sandbox Code Playgroud)

计时器

Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
    // Code
}
Run Code Online (Sandbox Code Playgroud)

DispatchSourceTimer

let timer = DispatchSource.makeTimerSource()

timer.schedule(deadline: .now() + .seconds(1))

timer.setEventHandler {
    // Code
}

timer.activate()
Run Code Online (Sandbox Code Playgroud)

所有计时器的利弊是什么?什么时候应该在另一个之上使用?哪种计时器方式最有效?我想出了以下几点:

计时器

优点:

  • 可以无效
  • 无需参考
  • 可以在预定的时间停止。

缺点:

  • 防止CPU闲置
  • 需要在具有运行循环的队列上运行(否则什么也没有发生,甚至没有断言触发器...)

DispatchSourceTimer

优点:

  • 可以取消
  • 无需运行循环

缺点:

  • 需要强大的参考,否则会立即被释放

异步之后

优点:-无需运行循环

缺点:-无法取消(我认为)

还有更多计时器吗?为什么有那么多计时器?我期望所有不同的计时器之间都存在真正的差异,但是我找不到它们。

您可以在这里阅读许多问题。主要问题是:什么计时器可用,在什么情况下应使用什么计时器?为什么?

Rob*_*ier 27

Timer是NSTimer的Swift桥,可以追溯到NeXTSTEP,早于Grand Central Dispatch(GCD)和DispatchSourceTimer之类的东西,DispatchSourceTimer直到10.6(采用dispatch_source_set_timer的形式)和dispatchAfter(采用的形式)才出现(dispatch_after)。

NSTimer基于运行循环,这是在GCD之前完成并发的主要方式。这是一个协作式并发系统,主要设计为在单个内核上的单个线程上运行(尽管它可以扩展到多线程环境)。

尽管运行循环在Cocoa中仍然非常重要,但它不再是管理并发的主要方法,甚至不再是首选方法。从10.6开始,GCD成为越来越受欢迎的方法(尽管在10.12时限中添加基于块的NSTimer API是一种受欢迎的现代化方法)。

在15秒的范围内,效率差异是无关紧要的。就是说,我不理解您的评论“计时器阻止CPU进入空闲状态”。我不相信那是真的。等待NSTimer触发时,CPU肯定仍将进入空闲状态。

我不会仅仅为了运行NSTimer而设置运行循环。您最好将它安排在主运行循环上,然后再DispatchQueue.async在其他队列上进行实际工作。

一般来说,我使用满足需求的最高级工具。这些都是苹果可能会在我进行最少更改的情况下不断优化的最佳方法。例如,NSTimer的启动日期会自动调整以提高能源效率。使用DispatchSourceTimer,您可以控制该leeway设置以获得相同的好处,但是要由您来设置(默认值为零,这对能源的影响最大)。当然,反之亦然。DispatchSourceTimer是最低级别的控件,可为您提供最大的控制权,因此,如果您需要它,那就可以使用它。

对于您的示例,我个人可能会使用一个Timer并将其作为块的一部分调度到私有队列。但是DispatchSourceTimer将是完全合适的。

asyncAfter确实是另一回事,因为它始终是一次性的。如果您想一次拍摄,那就太好了,但是如果您想重复一次,它会改变一切。如果您只是在代码块中调用asyncAfter进行重复,那么它将在您上一次完成操作之后15秒,而不是间隔15秒。前者会随着时间的流逝而逐渐漂移。设计问题是这样的:如果由于某种原因您的任务花了5秒钟完成,您是否希望下一次火灾事件在结束后15秒钟内发生,还是希望每个火灾事件之间保持15秒钟不变?您在那里选择将确定哪个工具正确。

此处,NSTimer事件总是比计划的要晚一些。具有回旋余地的GCD事件可以早一点或迟一点。实际上,没有“准时”之类的东西(这是一个零长度的时间段;您不会碰到它)。因此,问题始终是是否被保证像NSTimer那样迟到,或者您可能像GCD那样有回旋余地。

  • @EricWang Run 循环还没有被 GCD 淘汰,NSTimer 也没有。如果您使用 ObjC,NSTimer 完全适合它一直擅长的用例。在 Swift 中,还有计时器。虽然运行循环不是管理并发的首选方式,但这并不意味着它们已经消失,并且与 (NS)Timer 关系不大,它仍然是一个非常好的工具。 (2认同)