意外的迭代性能下降

时间:2014-02-07 22:43:41

标签: ios objective-c performance loops iteration

我目前正在为地图视图中的兴趣点开发一个群集框架。 为了生成集群,我目前正在使用一种缓慢但非常精确的算法。

while(self.clusteringData.count>=2){
    minDistance = DBL_MAX;
    for (ClusterAnnotation *objectA in self.clusteringData) {
        for (ClusterAnnotation *objectB in self.clusteringData) {
            if (objectA != objectB) {

                locationA.latitude = objectA.latitude;
                locationA.longitude = objectA.longitude;
                locationB.latitude = objectB.latitude;
                locationB.longitude = objectB.longitude;

                CLLocationDistance distance = [ClusterBuilder distanceBetweenLocation:locationA andLocation:locationB];
                if(distance < minDistance){
                    minDistance = distance;
                    left = objectA;
                    right = objectB;

                    if(minDistance == 0.0){
                        break;
                    }
                }
            }
        }
        if(minDistance == 0.0){
            break;
        }
    }
    [self notifyDelegateClusteringProgress:((float)i/(float)j)];

    ClusterTree* newRoot = [[ClusterTree alloc] initWithLeftClusterAnnotation:left rightClusterAnnotation:right];
    [newRoot setDistance:minDistance];
    [self.clusteringData addObject:newRoot];

    [self.clusteringData removeObject:left];
    [self.clusteringData removeObject:right];

    left = nil;
    right = nil;
    root = newRoot;
}

第一次迭代非常快 - 即使它们应该是最慢的。然而,每次迭代时性能会变差,然后随着留给群集的项目减少而变得更好。

我知道在使用O(n ^ 3)算法时我不能期望良好的性能,但是第一次迭代需要大约0.009秒,并且该时间随着每次迭代而增加(即使它应该减少因为算法减少了数据每次迭代1项)。 我无法向自己解释为什么会这样。

我确定了while循环的每次迭代需要1000个项目的时间。 http://pastebin.com/8XsZuEks

群集线程在DISPATCH_QUEUE_PRIORITY_HIGH上运行,并在整个群集过程中使用99%的CPU。 在主提示上运行该进程并未修复性能下降。所以我猜它不是GCD /优先问题。

2 个答案:

答案 0 :(得分:1)

你的迭代循环内置了一些中断,这意味着它并不总是每次都完成整个数组。性能变化是由于填充的数组和中断。

试想一下,如果你没有那些休息时间,每次迭代花费超过1.3秒(就像链接中最糟糕的情况一样)......

答案 1 :(得分:0)

尝试打印列表中的对象数以及迭代时间。也许奇怪的事情发生在对象的数量上?

除此之外,在进行任何优化工作之前,显然性能分析很重要。

只有1000个对象,这可能是浪费时间,但您可以考虑使用IMP函数指针调用替换内部循环体中的Objective-C消息调用。我认为常规C调用比消息传递快4-5倍。就时钟周期而言,没有太大差异,但如果您的数据有可能增长,那么它可能是值得的。