Ist Ihnen aufgefallen, dass dispatch_after auf iOS-Geräten ~ 10% zu langsam ausgeführt wird?

In letzter Zeit habe ich dispatch_after anstelle von performSelector verwendet: withObject: afterDelay, wenn ich nach einer Verzögerung einen Code auslösen möchte. Der Code ist sauberer, er hat Zugriff auf den umschließenden Bereich, ich kann den Code in die Zeile setzen, anstatt eine Wegwerfmethode usw. zu schreiben.

Mein Code könnte so aussehen:

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

Vor kurzem habe ich jedoch festgestellt, dass die Zeit bis zur Ausführung dieses Codes ungefähr 10% langsamer als angefordert zu sein scheint. Wenn ich um eine Verzögerung von 10 Sekunden bitte, wird mein Block ungefähr 11 Sekunden später ausgeführt. Dies ist auf einem iOS-Gerät. Die Zeiten scheinen auf dem Simulator ziemlich genau zu stimmen.

Der Code, mit dem ich das teste, ist ziemlich einfach:

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

Ich habe auf Geräten von iOS 4S bis iPad Air getestet und die zusätzliche Verzögerung ist ziemlich konstant. Ich habe noch nicht auf einem älteren Gerät wie einem iPhone 4 oder einem iPad 2 getestet, obwohl ich das bald tun werde.

Ich könnte 20-50 ms "Slop" in der Verzögerung erwarten, aber ein konstantes Überschwingen von 10% - 11% ist ungerade.

Ich habe meinem Code einen "Fudge-Faktor" hinzugefügt, der die zusätzliche Verzögerung berücksichtigt, aber ich finde es überraschend:

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

Ich sollte wahrscheinlich mehr analysieren und sehen, ob es eine feste Zunahme der Verzögerung plus einen Verzögerungsfaktor oder eine direkte prozentuale Verzögerung gibt, oder vielleicht eine nichtlineare Skalierung des Fehlers, aber im Moment scheint ein einfacher Multiplikator ziemlich gut zu funktionieren.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage