NSSet 迭代所需时间比 NSMutableArray 迭代更长,而 NSArray 迭代所需时间比 NSMutableArray 迭代更长。

4
尽管我查阅了以下NSSetNSMutableArrayNSFastEnumeration文档,但我无法找到满足以下场景的令人满意的来源:
在这里,NSMutableArrayNSArrayNSSet包含相等的10000000个对象。
for (NSString *strIn in MutableArray) //NSMutableArray
{
    // same Implementation
}
NSLog(@"Time for Mutable Array  %d Iteration : %f",ObjectCount,[[NSDate date]timeIntervalSinceDate:startDate]);
startDate = [NSDate date];
for (NSString *strIn in array)  //NSArray
{
    // same Implementation
}
NSLog(@"Time for  NSArray  %d Iteration : %f",ObjectCount,[[NSDate date]timeIntervalSinceDate:startDate]);
startDate = [NSDate date];
for (NSString *strIn in Set) //NSSet
{
    // same Implementation
}
NSLog(@"Time for Set  %d Iteration : %f",ObjectCount,[[NSDate date]timeIntervalSinceDate:startDate]);

输出结果如下: NSMutableArray 10000000次迭代所需时间:0.048785秒 NSArray 10000000次迭代所需时间:0.390537秒 NSSet 10000000次迭代所需时间:4.684203秒
为什么NSSetNSArray的迭代时间差别如此之大。
请详尽回答。
编辑: 我已经找到了上述迭代时间背后的真正原因,那是由于数组和集合中元素数量不相等。我在这里发布了实际问题。同时,我也可以在这里发布相同的问题,但似乎对于这个页面来说太过不规范,而且造成这种情况的原因也有所偏离。再次感谢所有人的回应。

非常有趣,为了验证您的测试程序,您是否尝试更改迭代顺序?这样可以确保外部因素(例如其他应用程序引起的临时性能下降等)不会影响您的结果。此外,实际上迭代几次并使用平均时间值也是很好的做法。 - lawicko
@lawicko:感谢您的评论。我已经以所有可能的3!种方式改变了迭代顺序,但大致上保持不变。此外,只有频繁重新执行会使迭代时间在微观层面上有所变化。 - itechnician
我会预期这个集合会比较慢,但是两个数组的值应该是相同的,因为它们的实现是相同的。很明显你的方法存在问题。 - Hot Licks
2个回答

3
我不同意你的结果:
#import <Foundation/Foundation.h>

#define COLLECTION_SIZE 10000000

static NSString *randomString() {
    unichar buffer[18];
    NSUInteger size = (arc4random() % 12) + 6;
    for (NSUInteger i = 0; i < size; i++) {
        buffer[i] = (arc4random() % 93) + '!';
    }
    return [[NSString alloc] initWithCharacters:buffer length:size];
}

static NSSet *createCollection(NSUInteger size) {
    NSMutableSet *collection = [[NSMutableSet alloc] init];
    for (NSUInteger i = 0; i < size; i++) {
        for (;;) {
            NSString *s = randomString();
            if (![collection member:s]) {
                [collection addObject:s];
                break;
            }
        }
    }
    return collection;
}

static NSTimeInterval timedIter(id<NSFastEnumeration> collection) {
    NSUInteger totalLength = 0;
    NSDate *startDate = [NSDate date];
    for (NSString *s in collection) {
        totalLength += [s length];
    }
    return [[NSDate date] timeIntervalSinceDate:startDate];
}

int main(int argc, const char **argv) {
    @autoreleasepool {
        NSSet *set = createCollection(COLLECTION_SIZE);
        NSArray *array = [set allObjects];
        NSMutableArray *mutArray = [[set allObjects] mutableCopy];

        NSLog(@"set iteration=%f", timedIter(set));
        NSLog(@"array iteration=%f", timedIter(array));
        NSLog(@"mutArray iteration=%f", timedIter(mutArray));
    }
    return 0;
}

$ clang -o itertime itertime.m -fobjc-arc -framework Foundation
$ ./itertime
2013-11-13 11:23:13.344 itertime[77576:707] set iteration=0.422592
2013-11-13 11:23:13.654 itertime[77576:707] array iteration=0.309387
2013-11-13 11:23:13.964 itertime[77576:707] mutArray iteration=0.309107

2
差异非常大。可能是因为您已经省略了循环体内容。我用1000万个NSNumbers做了同样的事情,差异要小得多。
Time for __NSArrayM: 0.334106
Time for __NSArrayI: 0.335368
Time for __NSSetI: 0.373651

您应该提供循环体,因为现在很难说为什么差异这么大。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接