GCD在哪些情况下会对旧设备产生负面的性能影响?

时间:2012-04-01 15:56:25

标签: iphone ios ipad concurrency grand-central-dispatch

我正在体验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

2 个答案:

答案 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开销,但让我觉得在创建和释放队列时明智地使用它将是谨慎的,并且也有助于诊断问题。