Вы заметили, что dispatch_after работает на 10% медленнее на устройствах iOS?

В последнее время я использовал dispatch_after вместо executeSelector: withObject: afterDelay, когда я хочу вызвать некоторый код после задержки. Код чище, у него есть доступ к закрытой области видимости, я могу поместить код в строку вместо написания одноразового метода и т. Д. И т. Д.

Мой код может выглядеть так:

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

Однако недавно я обнаружил, что время выполнения этого кода, по-видимому, работает примерно на 10% медленнее, чем запрошено. Если я запрашиваю задержку в 10 секунд, мой блок исполняется примерно через 11 секунд. Это на устройстве iOS. Кажется, что времена на симуляторе совпадают.

Код, который я использую для тестирования, довольно прост:

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, хотя скоро сделаю это.

Я мог бы ожидать 20–50 мс «спада» в задержке, но постоянное превышение на 10–11% является странным.

Я добавил в свой код «коэффициент выдумки», который корректирует дополнительную задержку, но я нахожу это удивительным:

#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.
  }
);

Я, вероятно, должен сделать больше анализа и посмотреть, есть ли фиксированное увеличение задержки плюс коэффициент задержки или прямая процентная задержка, или, возможно, некоторая нелинейная шкала ошибки, но сейчас простой множитель, кажется, работает довольно хорошо.