DispatchSourceTimer、Timer 和 asyncAfter 之间的区别? [英] Difference between DispatchSourceTimer, Timer and asyncAfter?

查看:22
本文介绍了DispatchSourceTimer、Timer 和 asyncAfter 之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力理解 DispatchSourceTimer定时器asyncAfter(在我的例子中用于安排需要每 X 秒运行一次的任务,尽管了解计时器的差异可能对有用)(或者除了列出的计时器之外,Swift 中还有其他(更有效的)调度机制吗?).

I am struggling to understand the key differences between DispatchSourceTimer, Timer and asyncAfter (in my case for scheduling a task that needs to be ran every X seconds, although understanding the differences in timers can be useful to) (Or is there another (more efficient) scheduling mechanism in Swift besides the listed timers?).

Timer 需要在它启动的当前队列上有一个活动的运行循环.DispatchSourceTimer 不需要.Timer 防止 CPU 进入空闲状态.这也适用于 DispatchSourceTimer/asyncAfter 吗?

A Timer needs an active run loop on the current queue it was started on. A DispatchSourceTimer does not need that. A Timer keeps the CPU from going into the idle state. Does this apply to DispatchSourceTimer/asyncAfter as well?

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

In what situation a Timer is preferred over a DispatchSourceTimer/asyncAfter? And of course the difference between all of them?

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

I want to schedule work every 15 seconds in my application on a private queue. This means I have to use DispatchSourceTimer because I am on a queue that is not the main thread (or add a runloop to the queue and use Timer). However, I do not see any benefit of even using a Timer in the first place. Maybe there is another operation that I can use that schedule work every X seconds on a private queue that is more efficient than a DispatchSourceTimer, but I did not came across a better solution.

DispatchSourceTimer 是否比 Timer 更有效?或者我应该继续使用 asyncAfter 的自调用方法?

Is a DispatchSourceTimer more efficient than a Timer? Or should I go on a self-calling method with asyncAfter?

这是创建计时器的代码.

This is the code to create the timers.

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()

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

Whats are the cons and pros of all the timers? When should I use one above the other? What timer way is the most efficient? I came up with the following:

优点:

  • 可以失效
  • 无需参考
  • 可以在预定时停止.

缺点:

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

优点:

  • 可以取消
  • 不需要运行循环

缺点:

  • 需要一个强引用,否则它会立即被释放

优点:- 不需要运行循环

Pros: - No run loop needed

缺点:- 不能取消(我认为)

Cons: - Can not be cancelled (I think)

还有更多计时器吗?为什么有这么多定时器?我预计所有不同的计时器之间会有一些真正的差异,但我找不到它们.

Are there even more timers? Why are there so many timers? I expected some real difference across all the different timers, but I couldn't find them.

这里有很多问题,您可以阅读.主要问题是:哪些计时器可用,我应该在什么情况下使用哪些计时器以及为什么?

Alot of questions here as you can read. The main question is: what timers are available and what timers should I use in what case and why?

推荐答案

Timer 是 NSTimer 的 Swift 桥梁,它可以追溯到 NeXTSTEP,早在 Grand Central Dispatch (GCD) 和诸如 DispatchSourceTimer 之类的东西之前,它没有一直到10.6(以dispatch_source_set_timer的形式)和dispatchAfter(以dispatch_after的形式).

Timer is a Swift bridge of NSTimer, which goes back to NeXTSTEP, long, long before Grand Central Dispatch (GCD) and things like DispatchSourceTimer, which didn't come along until 10.6 (in the form of dispatch_source_set_timer) and dispatchAfter (in the form of dispatch_after).

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

NSTimer is based on the run loop, which was the primary way that concurrency was done until GCD. It's a cooperative concurrency system, designed primary to run on a single thread on a single core (though it can be expanded to multi-threaded environments).

虽然运行循环在 Cocoa 中仍然非常重要,但它不再是管理并发的主要方式,甚至不再是首选方式.自 10.6 以来,GCD 已成为越来越受欢迎的方法(尽管在 10.12 时间范围内添加基于块的 NSTimer API 是一种受欢迎的现代化).

While the run loop is still very important in Cocoa, it is no longer the primary, or even preferred, way to manage concurrency. Since 10.6, GCD has been the increasingly preferred approach (though adding a block-based NSTimer API in the 10.12 timeframe was a welcome modernization).

在 15 秒的范围内,效率差异是无关紧要的.也就是说,我不明白您的评论计时器使 CPU 不会进入空闲状态".我不相信这是真的.在等待 NSTimer 触发时,CPU 肯定仍会进入空闲状态.

On the scale of 15 seconds, the efficiency differences are pretty irrelevant. That said, I don't understand your comment "A Timer keeps the CPU from going into the idle state." I don't believe that's true. The CPU will definitely still go into the idle state when waiting on an NSTimer to fire.

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

I would not set up a run loop just to run an NSTimer. You would be much better off scheduling it on the main runloop and then using DispatchQueue.async to do the actual work on some other queue.

作为一个广泛的规则,我使用满足需要的最高级别的工具.随着时间的推移,Apple 可能会优化最好的那些,而我所做的更改最少.例如,NSTimer 的触发日期会自动调整以提高能源效率.使用 DispatchSourceTimer,您可以控制 leeway 设置以获得相同的好处,但由您来设置它(默认值为零,这对能量影响最严重).当然,反过来也是如此.DispatchSourceTimer 是最低级别,为您提供最大程度的控制权,因此,如果您需要,就可以使用它.

As a broad rule, I use the highest-level tool that meets the need. Those are the ones that Apple is likely to optimize the best over time with me making the fewest changes. For example, NSTimer fire dates are automatically adjusted to improve energy efficiency. With DispatchSourceTimer, you get control over the leeway setting to get the same benefit, but it's up to you to set it (the default is zero, which has the worst energy impact). Of course, the reverse is also true. DispatchSourceTimer is the lowest level and gives you the most control, so if that's what you need, that's the one to use.

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

For your example, I'd personally probably use a Timer and just dispatch to the private queue as part of the block. But a DispatchSourceTimer would be completely appropriate.

asyncAfter 真的是另一回事,因为它总是一次性的.如果你想要一次,那很好,但如果你想重复,它会改变事情.如果你只是在块中调用 asyncAfter 来重复,它会在你最后一次完成后 15 秒,而不是间隔 15 秒.随着时间的推移,前者往往会漂移得有点晚.设计问题是这样的:如果由于某种原因您的任务需要 5 秒才能完成,您希望下一个火灾事件在该事件结束后的 15 秒内发生,还是希望每个火灾事件之间有一个恒定的 15 秒?您在那里的选择将决定哪个工具是正确的.

asyncAfter is really a different thing, since it's always a one-shot. That's great if you want a one-shot, but it changes things if you want to repeat. If you just call asyncAfter in the block to repeat, it's going to be 15 seconds after the last time you finished, rather than being spaced 15 seconds apart. The former will tend to drift a bit late over time. The design question is this: if for some reason your task took 5 seconds to complete, would you want the next fire event to happen 15 seconds from the end of that, or would you want a constant 15 seconds between each fire event? Your choice there will determine which tool is correct.

有一点需要注意,NSTimer 事件总是比预定的晚一点.带有回旋余地的 GCD 事件可能会早一点或晚一点.实际上,没有准时"这样的事情(这是一个零长度的时期;你不会达到它).所以问题总是在于你是承诺像 NSTimer 那样迟到,还是像 GCD 那样早有余地.

As a slight note there, NSTimer events are always a little later than they are scheduled. GCD events with a leeway setting can be a little early or a little late. As a practical matter, there's no such thing as being "on time" (that's a period of zero length; you're not going to hit it). So the question is always whether you are promised to be late like NSTimer, or you might be early like GCD with leeway.

这篇关于DispatchSourceTimer、Timer 和 asyncAfter 之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆