DispatchSourceTimer、Timer 和 asyncAfter 之间的区别?
Difference between DispatchSourceTimer, Timer and asyncAfter?
我正在努力理解 DispatchSourceTimer, Timer and asyncAfter 之间的主要区别( 在我的情况下,安排一个需要每 X 秒 运行 的任务,尽管理解计时器对很有用)(或者除了列出的计时器之外,Swift中是否还有另一种(更有效的)调度机制?)。
A Timer
需要在其启动的当前队列上有一个活动的 运行 循环。 DispatchSourceTimer
不需要那个。 Timer
防止 CPU 进入空闲状态。这也适用于 DispatchSourceTimer
/asyncAfter
吗?
在什么情况下 Timer
优于 DispatchSourceTimer
/asyncAfter
?当然还有它们之间的区别?
我想在我的应用程序中每 15 秒安排一次工作在私有队列上。这意味着我必须使用 DispatchSourceTimer
因为我在一个不是主线程的队列上(或者向队列添加一个 运行 循环并使用 Timer
)。但是,我什至一开始就没有看到使用 Timer
有任何好处。也许还有另一种操作,我可以在私有队列上每隔 X 秒使用一次调度工作,这比 DispatchSourceTimer
更有效,但我没有找到更好的解决方案。
DispatchSourceTimer
是否比 Timer
更有效?还是我应该使用 asyncAfter
?
进行自我调用?
这是创建计时器的代码。
asyncAfter
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(2)) {
// Code
}
定时器
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
// Code
}
DispatchSourceTimer
let timer = DispatchSource.makeTimerSource()
timer.schedule(deadline: .now() + .seconds(1))
timer.setEventHandler {
// Code
}
timer.activate()
所有计时器的优缺点是什么?我什么时候应该在另一个之上使用一个?哪种定时器方式最有效?我想到了以下内容:
计时器
优点:
- 可以失效
- 无需参考
- 可以在计划时停止。
缺点:
- 防止CPU闲置
- 需要 运行 在具有 运行 循环的队列上(否则什么也不会发生,甚至没有断言触发器...)
DispatchSourceTimer
优点:
- 可以取消
- 不需要 运行 循环
缺点:
- 需要一个强引用,否则它会立即被释放
asyncAfter
优点:
- 不需要 运行 循环
缺点:
- 无法取消(我认为)
还有更多的计时器吗?为什么有这么多定时器?我希望所有不同的计时器都有一些真正的区别,但我找不到它们。
这里有很多问题,您可以阅读。主要问题是:哪些计时器可用,在什么情况下我应该使用哪些计时器以及为什么?
Timer 是 NSTimer 的 Swift 桥接器,它可以追溯到 NeXTSTEP,远早于 Grand Central Dispatch (GCD) 和诸如 DispatchSourceTimer 之类的东西,它直到 10.6 才出现(形式为dispatch_source_set_timer) 和 dispatchAfter (以 dispatch_after 的形式).
NSTimer 基于 运行 循环,这是在 GCD 之前完成并发的主要方式。它是一个协作并发系统,主要设计用于 运行 单核单线程(尽管它可以扩展到多线程环境)。
虽然 运行 循环在 Cocoa 中仍然非常重要,但它不再是管理并发的主要方式,甚至不再是首选方式。自 10.6 以来,GCD 一直是越来越受欢迎的方法(尽管在 10.12 时间框架中添加基于块的 NSTimer API 是一个受欢迎的现代化)。
在 15 秒的范围内,效率差异是无关紧要的。也就是说,我不明白你的评论 "A Timer keeps the CPU from going into the idle state." 我不相信那是真的。 CPU 在等待 NSTimer 触发时肯定仍会进入空闲状态。
我不会为 运行 NSTimer 设置一个 运行 循环。您最好将其安排在主 运行 循环上,然后使用 DispatchQueue.async
在其他队列上完成实际工作。
一般来说,我会使用满足需要的最高级别的工具。随着时间的推移,这些是 Apple 可能会优化得最好的,而我所做的更改最少。例如,NSTimer 的触发日期会自动调整以提高能源效率。使用 DispatchSourceTimer,您可以控制 leeway
设置以获得相同的好处,但设置它取决于您(默认值为零,这对能源影响最大)。当然,反之亦然。 DispatchSourceTimer 是最低级别并为您提供最多的控制权,因此如果这是您需要的,那就是使用它。
对于您的示例,我个人可能会使用计时器并作为块的一部分发送到专用队列。但是 DispatchSourceTimer 是完全合适的。
asyncAfter 确实是另一回事,因为它始终是一次性的。如果你想要一次性,那很好,但如果你想重复,它会改变事情。如果您只是在要重复的块中调用 asyncAfter,它将在您上次完成后 15 秒,而不是间隔 15 秒。随着时间的推移,前者往往会漂移得晚一些。设计问题是这样的:如果由于某种原因您的任务需要 5 秒才能完成,您是否希望下一次火灾事件在该事件结束后 15 秒发生,或者您希望每次火灾事件之间保持恒定的 15 秒?您在那里的选择将决定哪个工具是正确的。
这里有个小提示,NSTimer 事件总是比计划的时间晚一点。有余地设置的GCD事件可以早一点也可以晚一点。实际上,没有 "on time" 这样的东西(这是一个零长度的周期;你不会碰到它)。所以问题始终是你是否承诺像NSTimer一样迟到,或者你可能像GCD那样有余地早
我正在努力理解 DispatchSourceTimer, Timer and asyncAfter 之间的主要区别( 在我的情况下,安排一个需要每 X 秒 运行 的任务,尽管理解计时器对很有用)(或者除了列出的计时器之外,Swift中是否还有另一种(更有效的)调度机制?)。
A Timer
需要在其启动的当前队列上有一个活动的 运行 循环。 DispatchSourceTimer
不需要那个。 Timer
防止 CPU 进入空闲状态。这也适用于 DispatchSourceTimer
/asyncAfter
吗?
在什么情况下 Timer
优于 DispatchSourceTimer
/asyncAfter
?当然还有它们之间的区别?
我想在我的应用程序中每 15 秒安排一次工作在私有队列上。这意味着我必须使用 DispatchSourceTimer
因为我在一个不是主线程的队列上(或者向队列添加一个 运行 循环并使用 Timer
)。但是,我什至一开始就没有看到使用 Timer
有任何好处。也许还有另一种操作,我可以在私有队列上每隔 X 秒使用一次调度工作,这比 DispatchSourceTimer
更有效,但我没有找到更好的解决方案。
DispatchSourceTimer
是否比 Timer
更有效?还是我应该使用 asyncAfter
?
这是创建计时器的代码。
asyncAfter
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(2)) {
// Code
}
定时器
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
// Code
}
DispatchSourceTimer
let timer = DispatchSource.makeTimerSource()
timer.schedule(deadline: .now() + .seconds(1))
timer.setEventHandler {
// Code
}
timer.activate()
所有计时器的优缺点是什么?我什么时候应该在另一个之上使用一个?哪种定时器方式最有效?我想到了以下内容:
计时器
优点:
- 可以失效
- 无需参考
- 可以在计划时停止。
缺点:
- 防止CPU闲置
- 需要 运行 在具有 运行 循环的队列上(否则什么也不会发生,甚至没有断言触发器...)
DispatchSourceTimer
优点:
- 可以取消
- 不需要 运行 循环
缺点:
- 需要一个强引用,否则它会立即被释放
asyncAfter
优点: - 不需要 运行 循环
缺点: - 无法取消(我认为)
还有更多的计时器吗?为什么有这么多定时器?我希望所有不同的计时器都有一些真正的区别,但我找不到它们。
这里有很多问题,您可以阅读。主要问题是:哪些计时器可用,在什么情况下我应该使用哪些计时器以及为什么?
Timer 是 NSTimer 的 Swift 桥接器,它可以追溯到 NeXTSTEP,远早于 Grand Central Dispatch (GCD) 和诸如 DispatchSourceTimer 之类的东西,它直到 10.6 才出现(形式为dispatch_source_set_timer) 和 dispatchAfter (以 dispatch_after 的形式).
NSTimer 基于 运行 循环,这是在 GCD 之前完成并发的主要方式。它是一个协作并发系统,主要设计用于 运行 单核单线程(尽管它可以扩展到多线程环境)。
虽然 运行 循环在 Cocoa 中仍然非常重要,但它不再是管理并发的主要方式,甚至不再是首选方式。自 10.6 以来,GCD 一直是越来越受欢迎的方法(尽管在 10.12 时间框架中添加基于块的 NSTimer API 是一个受欢迎的现代化)。
在 15 秒的范围内,效率差异是无关紧要的。也就是说,我不明白你的评论 "A Timer keeps the CPU from going into the idle state." 我不相信那是真的。 CPU 在等待 NSTimer 触发时肯定仍会进入空闲状态。
我不会为 运行 NSTimer 设置一个 运行 循环。您最好将其安排在主 运行 循环上,然后使用 DispatchQueue.async
在其他队列上完成实际工作。
一般来说,我会使用满足需要的最高级别的工具。随着时间的推移,这些是 Apple 可能会优化得最好的,而我所做的更改最少。例如,NSTimer 的触发日期会自动调整以提高能源效率。使用 DispatchSourceTimer,您可以控制 leeway
设置以获得相同的好处,但设置它取决于您(默认值为零,这对能源影响最大)。当然,反之亦然。 DispatchSourceTimer 是最低级别并为您提供最多的控制权,因此如果这是您需要的,那就是使用它。
对于您的示例,我个人可能会使用计时器并作为块的一部分发送到专用队列。但是 DispatchSourceTimer 是完全合适的。
asyncAfter 确实是另一回事,因为它始终是一次性的。如果你想要一次性,那很好,但如果你想重复,它会改变事情。如果您只是在要重复的块中调用 asyncAfter,它将在您上次完成后 15 秒,而不是间隔 15 秒。随着时间的推移,前者往往会漂移得晚一些。设计问题是这样的:如果由于某种原因您的任务需要 5 秒才能完成,您是否希望下一次火灾事件在该事件结束后 15 秒发生,或者您希望每次火灾事件之间保持恒定的 15 秒?您在那里的选择将决定哪个工具是正确的。
这里有个小提示,NSTimer 事件总是比计划的时间晚一点。有余地设置的GCD事件可以早一点也可以晚一点。实际上,没有 "on time" 这样的东西(这是一个零长度的周期;你不会碰到它)。所以问题始终是你是否承诺像NSTimer一样迟到,或者你可能像GCD那样有余地早