Czy zauważyłeś, że dispatch_after działa ~ 10% za wolno na urządzeniach z systemem iOS?

Ostatnio używam dispatch_after zamiast performSelector: withObject: afterDelay, kiedy chcę wyzwolić jakiś kod po pewnym czasie. Kod jest czystszy, ma dostęp do otaczającego zakresu, mogę umieścić kod w linii zamiast pisać metodę wyrzucania itp. Itd.

Mój kod może wyglądać tak:

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

Niedawno jednak odkryłem, że czas na wykrycie tego kodu wydaje się działać dość konsekwentnie około 10% wolniej niż zażądano. Jeśli poproszę o opóźnienie 10 sekund, mój blok zostanie wykonany około 11 sekund później. To jest na urządzeniu z systemem iOS. Czasy wydają się pasować dość dokładnie na symulatorze.

Kod, którego używam do testowania tego, jest całkiem prosty:

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

Przetestowałem na urządzeniach z iOS 4S do iPada Air, a dodatkowe opóźnienie jest dość spójne. Jeszcze nie testowałem na starszym urządzeniu, takim jak iPhone 4 lub iPad 2, chociaż wkrótce to zrobię.

Mogę spodziewać się 20-50 ms „opóźnienia” w opóźnieniu, ale spójne 10% - 11% przeregulowania jest dziwne.

Dodałem „kod krówki” do mojego kodu, który dostosowuje się do dodatkowego opóźnienia, ale wydaje mi się to zaskakujące:

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

Prawdopodobnie powinienem zrobić więcej analiz i sprawdzić, czy istnieje stały wzrost opóźnienia plus współczynnik opóźnienia lub proste procentowe opóźnienie, a może jakaś nieliniowa skala błędu, ale na razie prosty mnożnik wydaje się całkiem dobrze.

questionAnswers(1)

yourAnswerToTheQuestion