我正在体验GCD的奇怪之处。
首先,我有一个执行繁重计算的方法,然后进行一些UI布局计算并根据结果更新UI。
每次调用此方法时,如果没有GCD,用户界面会冻结约 0.5秒。
所以我去GCD做了这个:
// INIT
// stored in ivar (called only once!)
dispatch_queue_t q = dispatch_queue_create("com.testcompany.myqueue", NULL);
// WORK
dispatch_async(q, ^(void) {
[self performHeavyCalculationAndUpdateUI]; // modifies self.calculationData
});
此更改后,该方法需要 2-5秒,直到更改出现在用户界面中。
串行队列中运行的-performHeavyCalculationAndUpdateUI:
中的工作代码以Robert Ryan suggested here的方式调用主队列(主线程)上的一些UI修改代码:
dispatch_async(dispatch_get_main_queue(), ^{
// Read ivars and objects used during calculation in the serial queue (problem?)
CalculationData *result = self.calculationData;
// UI updates like [foo addSubview:bar];
});
在主队列上,我还读了一些在串行后台队列中计算时使用的ivars和对象。这可能是个问题吗?
在出现问题之前,仍需要大约2-5秒。比没有GCD要长得多。
除了这里,我没有在其他任何地方使用GCD。
是否有其他人遇到过GCD的这类问题并且知道解决方案?
几小时后我发现:The Reason。
答案 0 :(得分:1)
您所描述的问题不是来自GCD,至少不是来自您发布的代码。我做了一个快速测试功能来记录切换队列所需的时间:
-(IBAction)beginWork:(id)sender{
NSTimeInterval buttonPushTime = [NSDate timeIntervalSinceReferenceDate];
// Defined as an ivar : dispatch_queue_t q;
// created as "q = dispatch_queue_create("com.testcompany.myqueue", NULL);" in viewDidLoad
dispatch_async(q, ^{
NSTimeInterval backgroundBeginTime = [NSDate timeIntervalSinceReferenceDate];
[NSThread sleepForTimeInterval:5.0];
NSTimeInterval backgroundEndTime = [NSDate timeIntervalSinceReferenceDate];
dispatch_async(dispatch_get_main_queue(), ^{
NSTimeInterval backOnMainThreadTime = [NSDate timeIntervalSinceReferenceDate];
NSLog(@"seconds to start on background thread = %f",backgroundBeginTime-buttonPushTime);
NSLog(@"seconds to perform in background = %f",backgroundEndTime-backgroundBeginTime);
NSLog(@"seconds to get main thread again = %f",backOnMainThreadTime-backgroundEndTime);
NSLog(@"total seconds = %f",backOnMainThreadTime-buttonPushTime);
});
});
}
然后我在我的iPod touch 2nd gen上运行了这个代码(一个可以说是非常古老的设备.iOS 4.2.1)。结果如下:
seconds to start on background thread = 0.001747
seconds to perform in background = 5.000142
seconds to get main thread again = 0.000190
total seconds = 5.002079
在这种情况下,队列切换的时间增加不到千分之二秒。我建议您添加一些类似的日志记录来查找延迟。
答案 1 :(得分:0)
BTW,您每次调用dispatch_queue_create
时都在执行performHeavyCalculationAndUpdateUI
吗?你是否多次进行这种繁重的计算?如果是这样,您可能希望确保只创建一次队列并根据需要调度它。 (通过将队列创建/发布与您发送的内容分开,也可以帮助您诊断导致性能问题的原因...... GDC开销或performHeavyCalculationAndUpdateUI
中的一些问题。最后,当您执行dispatch_release
时'完成了队列?
有一些GCD开销,但让我觉得在创建和释放队列时明智地使用它将是谨慎的,并且也有助于诊断问题。