嵌套枚举中的快速枚举比for循环慢(带有测试结果)?

时间:2012-07-11 13:42:39

标签: objective-c arrays performance for-loop fast-enumeration

我知道有一些主题似乎是关于完全相同的事情,但我没有找到一个真正关于我想要的东西。

所以我很好奇并希望将Fast Enumeration的性能与NSEnumerator和for循环进行比较。 (这是经常被问到的部分)

首先我比较了快速枚举:

for(NSNumber *number in testArray)
{
    assert(number);
}

NSEnumerator:

NSEnumerator *enumerator = [testArray objectEnumerator];
NSNumber *number;
while (number = [enumerator nextObject]) 
{
    assert(number);
}

for Loop:

for(NSUInteger i = 0; i < [testArray count]; i++)
{
    NSNumber *number = [testArray objectAtIndex:i];
    assert(number);
}

我的testArray是一个由0到1,000,000的NSNumbers组成的数组,我在测试后100次运行测试并计算每次测试的平均运行时间。

我也在iPad 2上运行它们

结果:(所有100次运行的平均时间)

  • 0.042687s 快速枚举
  • 0.582072s NSEnumerator
  • 0.627318s for-loop

正如预期的那样,Fast Enumeration是迄今为止最快的,而NSEnumerator仍然比for-loop快一点,但这是为了枚举退出一个大型数组

所以这里不是那么频繁的问题:

实际上我对其他内容感兴趣:数组中的枚举将数组中的每个对象相互比较

首次使用嵌套for循环:

for(int i = 0; i < [testArray count]-1; i++)
{
    NSNumber *number = [testArray objectAtIndex:i];
    for(int j = i+1; j < [testArray count]; j++)
    {
        NSNumber *innerLoopNumber = [testArray objectAtIndex:j];
        assert(innerLoopNumber);
        assert(number);
    }
}

对于这些测试,我必须减少数组的大小和运行次数,以便在合理的时间内完成它们,因为迭代次数当然会增加O(n ^ 2)。 所以我用一个带有5.000个NSNumbers的数组运行它们并重复测试5次。

结果: 7.360645s 一次运行

所以我想,当然,快速枚举应该更快。但是要实现三角形模式以避免两次比较每对元素,我不得不在外循环中将Fast Enumeration与内循环中的NSEnumerator混合

for(NSNumber *number in testArray)
{
    NSEnumerator *reverseEnumterator = [testArray reverseObjectEnumerator];
    NSNumber *innerLoopNumber = reverseEnumterator.nextObject;
    while(innerLoopNumber && ![innerLoopNumber isEqualToNumber:number])
    {
        innerLoopNumber = reverseEnumterator.nextObject;
        assert(innerLoopNumber);
        assert(number);
    }
}

令我惊讶的是,这个速度要慢得多: 18.086980s 一次运行

然后我尝试了混合版本,使用Fast Enumeration作为外部循环,使用for循环作为内部循环:

int counter = 0;
for(NSNumber *number in testArray)
{
    for(int j = counter +1; j < [testArray count]; j++)
    {
        NSNumber *innerLoopNumber = [testArray objectAtIndex:j];
        assert(innerLoopNumber);
        assert(number);
    }
    counter++;
}

结果: 7.079600s 1次运行

比普通的for循环略快一些。

一个地方的数字:

  • 07.360645s for-Loop
  • 07.079600s 混合
  • 18.086980s 快速枚举

所以我想知道,为什么?快速枚举是否仅在“未中断”时才能正常工作,NSEnumerator的使用是否会干扰快速枚举? 或者我只是遗漏了一些东西而且我的方法错了?

1 个答案:

答案 0 :(得分:3)

您在快速枚举循环中调用其他方法。 Objective-c具有非平凡的方法调用开销,因此您的问题在于嵌套循环的设置。正如您所看到的,快速枚举+ for循环比循环+ for循环更快,在这里您可以避免其他方法调用。