您是否注意到dispatch_after在iOS设备上运行速度慢〜10%? [英] Have you noticed that dispatch_after runs ~10% too slow on iOS devices?

查看:108
本文介绍了您是否注意到dispatch_after在iOS设备上运行速度慢〜10%?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我一直在使用dispatch_after而不是performSelector:withObject:afterDelay,当我想在延迟后触发一些代码时。代码更清晰,可以访问封闭范围,我可以将代码放入内联而不是编写丢弃方法等等。

Lately I've been using dispatch_after instead of performSelector:withObject:afterDelay when I want to trigger some code after a delay. The code is cleaner, it has access to the enclosing scope, I can put the code in-line instead of writing a throw-away method, etc, etc.

My代码可能如下所示:

My code might look like this:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
  delay * NSEC_PER_SEC),
  dispatch_get_main_queue(),
  ^{
    //Delayed-execution code goes here.
  }
);

但是,我最近发现这段代码的执行时间似乎非常一致比要求慢10%。如果我要求延迟10秒,我的块将在11秒后执行。这是在iOS设备上。时间似乎在模拟器上非常接近。

However, I recently discovered that the time-to-excution from this code seems to run pretty consistently about 10% slower than requested. If I ask for a delay of 10 seconds, my block gets executed about 11 seconds later. This is on an iOS device. The times seem to match quite closely on the simulator.

我用来测试它的代码非常简单:

The code I'm using to test this is pretty simple:

NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
  delay * NSEC_PER_SEC),
  dispatch_get_main_queue(),
  ^{
    NSTimeInterval actualDelay = [NSDate timeIntervalSinceReferenceDate] - startTime;
    NSLog(@"Requested delay = %.3f. Atual delay = %.3f", delay, actualDelay);
    //Delayed-execution code goes here.
  }
);

我已经在从iOS 4S到iPad Air的设备上进行了测试,额外延迟非常一致。我还没有在像iPhone 4或iPad 2这样的旧设备上进行测试,虽然我很快就会这样做。

I've tested on devices from an iOS 4S to an iPad Air and the extra delay is pretty consistent. I haven't yet tested on an older device like an iPhone 4 or an iPad 2, although I will do that soon.

我可能期望20-50毫秒的 slop在延迟,但一致的10% - 11%的超调是奇怪的。

I might expect 20-50 ms of "slop" in the delay, but a consistent 10% - 11% overshoot is odd.

我在我的代码中添加了一个软糖因子,可以调整额外的延迟,但我觉得很惊讶:

I've added a "fudge factor" to my code that adjusts for the extra delay, but I find it surprising:

#define  delay_fudge 0.912557 //Value calculated based on averages from testing.


NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
  delay * delay_fudge *  NSEC_PER_SEC),
  dispatch_get_main_queue(),
  ^{
    NSTimeInterval actualDelay = [NSDate timeIntervalSinceReferenceDate] - startTime;
    NSLog(@"Requested delay = %.3f. Actual delay = %.3f", delay, actualDelay);
    //Delayed-execution code goes here.
  }
);

我应该做更多的分析,看看延迟是否有固定的增加加上延迟系数或直接百分比延迟,或者可能是错误的一些非线性比例,但现在一个简单的乘数似乎做得很好。

I should probably do more analysis and see if there is a fixed increase in delay plus a delay factor or a straight percent delay, or perhaps some non-linear scale to the error, but for now a simple multiplier seems to do pretty well.

推荐答案

您可能听说过计时器合并和App Nap - 这有助于降低功耗。

You may have heard about Timer Coalescing and App Nap - which helps to reduce power consumption.

您在这里观察的是延迟系统事件达到某个余地值的效果,以便能够执行它们一起在一个时间点,定时器合并。这将增加CPU在功耗降低模式上的持续时间。

What you are observing here is the effect of delaying system events up to a certain "leeway value" in order to be able to execute them all together at one point in time, "Timer Coalescing". That will increase the duration the CPU can dwell on its power reduced mode.

对于调度lib,有一个标志可用于提高余地的准确性值,这也最终影响计时器的准确性(见下文)。我不认为让定时器不必要准确是个好主意 - 例如移动设备。

For dispatch lib, there is a flag which can be used to increase the accuracy of the "leeway value", which also affects eventually the accuracy of a timer (see below). I don't think its a good idea to make timers unnecessary accurate - for mobile devices for example.

我的怀疑是, dispatch_after 将使用具有特定余地值的调度计时器,这是实现定义的。

My suspicion is, that dispatch_after will use a dispatch timer with a certain leeway value set, which is implementation defined.

您可以使用 dispatch_source_set_timer()在调度库中实现非常准确的计时器,您还可以在其中指定余地价值。

You can implement quite accurate timers with dispatch lib, using dispatch_source_set_timer(), where you can also specify the "leeway value".

参见: dispatch / source.h

/*!
 * @typedef dispatch_source_timer_flags_t
 * Type of dispatch_source_timer flags
 *
 * @constant DISPATCH_TIMER_STRICT
 * Specifies that the system should make a best effort to strictly observe the
 * leeway value specified for the timer via dispatch_source_set_timer(), even
 * if that value is smaller than the default leeway value that would be applied
 * to the timer otherwise. A minimal amount of leeway will be applied to the
 * timer even if this flag is specified.
 *
 * CAUTION: Use of this flag may override power-saving techniques employed by
 * the system and cause higher power consumption, so it must be used with care
 * and only when absolutely necessary.
 */

#define DISPATCH_TIMER_STRICT 0x1

...

 * Any fire of the timer may be delayed by the system in order to improve power
 * consumption and system performance. The upper limit to the allowable delay
 * may be configured with the 'leeway' argument, the lower limit is under the
 * control of the system.
 *

这篇关于您是否注意到dispatch_after在iOS设备上运行速度慢〜10%?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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