2012-07-11 83 views
4

我知道有相当多的话题似乎是关于完全相同的东西,但我没有找到真正与我想要的有关的话题。快速枚举比嵌套枚举中的for循环慢(带有测试结果)?

所以我很好奇,想要比较快速枚举到NSEnumerator和for循环的性能。 (这是要求相当频繁的部分)

首先,我比较快速计数:

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

NSEnumerator:

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

for循环:

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

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

我也跑了他们对我的iPad 2

结果:(指所有100个运行时间)

  • 0.042687s快速计数
  • 0.582072s NSEnumerator
  • 0.627318s for-loop

正如预期的那样,快速计数是迄今为止速度最快,而NSEnumerator仍然是一个有点快于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 1运行

所以我想,当然,快速列举应该会更快。但要实现三角模式,以避免两次比较每个元素对,我不得不在外环与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 1个运行

我然后试图混合版本,以及,使用快速枚举的外环和一个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-loop稍快。

在一个地方的数字:

  • 07.360645s for循环
  • 07.079600s混合
  • 18.086980s快速计数

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

+0

请注意,在'for'循环的每次迭代中,您都冗余地调用一个方法'[testArray count]'。 – echristopherson 2012-07-11 21:03:04

+0

根据Apple的文档,当使用for-loop:“在每个循环迭代中,它会调度一条消息来获取数组中的项目数量,这是浪费的。如果数组中项目的数量永不改变,您可以分配该值的一个变量,并使用,而不是“ – user523234 2013-11-27 14:44:03

回答

3

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

+0

嗯,我明白你的观点。平等检查在其他结构中不是必需的。但是检查是什么使得n^2次迭代和(n^2)/ 2次迭代之间的差异。所以它将取决于循环中实际操作的成本,但在我看来,对于这种情况,嵌套的快速枚举结构根本不适用。 – MeXx 2012-07-11 14:07:33

+0

尽量不要进行平等检查,我敢打赌,快速枚举的速度会比其他类型的检查一半多两倍,而没有额外的调用开销。 – Dustin 2012-07-11 14:10:52

+0

我试过了:15.004834s,比比较快了一点,但仍几乎是其他解决方案的两倍。如果我把真正的工作放在内部循环中,而不仅仅是断言,它通过内部循环两次的事实变得更加昂贵。我发现了一些更有趣的事情:在outerLoop中创建一个subarrayWithRange,然后快速枚举这个实现相同的事情,但比2.626523s更快,比for循环快两倍以上双快速枚举 – MeXx 2012-07-11 14:45:30