我遇到了一些奇怪的Grand Central Dispatch计时器行为。它打破了它的射击时间并冻结了几秒钟。虽然我需要ping我的服务器以保持“在线”,但这种行为非常不合适。
这里是计时器创建代码。
// pingTimer and pingQueue are class members
- (void)createPingTimerSource
{
// check timer exists
if(pingTimer)
{
// suspend source and cancel
[self setPingTimerSuspended:YES];
dispatch_source_cancel(pingTimer);
}
// check having queue, create if doesn't exist
if(!pingQueue)
pingQueue = dispatch_queue_create(kDispatchTimerQueueLabel, NULL);
// create timer dispatch source
pingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, pingQueue);
dispatch_source_set_timer(pingTimer, dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_MSEC), 5*NSEC_PER_MSEC, NSEC_PER_SEC/10);
// set event handler
dispatch_source_set_event_handler(pingTimer,^{
printf("[%llu] gcd timer fired.\n", mach_absolute_time()/NSEC_PER_SEC);
dispatch_async(dispatch_get_main_queue(), ^{
[self sendPingToServer];
});
});
// set cancel handler
dispatch_source_set_cancel_handler(pingTimer, ^{
// release dispatch source if exists
if(pingTimer)
dispatch_release(pingTimer);
// check timer queue exists and release if does
if(pingQueue)
dispatch_release(pingQueue);
});
}
这里是日志控制台拍摄的。
感谢您的帮助。
答案 0 :(得分:1)
dispatch_queue_create
不保证它为处理块创建独立的线程。
以下是Apple documentation的引用 队列未绑定到任何特定的执行线程 提交给独立队列的块可以同时执行。
因此,这意味着如果您有许多处于压力下的队列,可能会导致您的pingQueue停止响应并执行具有延迟的块。
答案 1 :(得分:1)
有几种可能性:
您的pingQueue
可能会被阻止执行某些操作,并且作为串行队列,它将无法执行新的调度块,直到先前的调度块完成并且队列再次可用。
您可以尝试记录ping例程的启动和停止,并确保问题实际上是计时器触发失败而不是队列被阻止,因此无法接受新的计时器请求。
如果您的应用不在前台,“App Nap”功能可能会尝试合并定时器以最大限度地减少功耗。因此,可能不会以您期望的频率调用定时器。
您可以通过提供DISPATCH_TIMER_STRICT
作为dispatch_source_create
的第三个参数来告知您的计时器不参与,尽管除非绝对需要(例如,与不能容忍计时器偏差的硬件接口),否则显然不鼓励这样做,如你失去了App Nap提供的节能。