【问题标题】:How does NSMutableArray achieve such high speed in fast enumerationNSMutableArray如何在快速枚举中达到如此高的速度
【发布时间】:2014-02-27 00:14:53
【问题描述】:

y 轴表示对列表/数组中每个节点的平均访问时间(以 ns 为单位)(访问所有元素的总时间除以元素的数量)。

x 轴表示被迭代的数组中元素的数量。

红色是NSMutableArray 的实现,蓝色是我的链表 (CHTape)。

在每个外部循环中,每个列表/数组都附加了一个空字符串@""。在内部循环中,检索每个列表/数组中的每个字符串,并对其进行计时和记录。在所有时间之后,我们在 Wolfram 语言输出中输出以生成绘图。

NSMutableArray 是如何取得如此惊人且一致的结果的?怎样才能达到类似的效果?

我的 NSFastEnumeration 实现:

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])stackBuffer count:(NSUInteger)len
{
    if (state->state == 0)
    {
        state->state = 1;
        state->mutationsPtr = &state->extra[1];
        state->extra[0] = (unsigned long)head;
    }

    CHTapeNode *cursor = (__bridge CHTapeNode *)((void *)state->extra[0]);

    NSUInteger i = 0;

    while ( cursor != nil && i < len )
    {
        stackBuffer[i] = cursor->payload;
        cursor = cursor->next;
        i++;
    }
    state->extra[0] = (unsigned long)cursor;

    state->itemsPtr = stackBuffer;

    return i;
}

完整的测试代码:

NSMutableArray *array = [NSMutableArray array];
CHTape *tape = [CHTape tape];

unsigned long long start;

unsigned long long tapeDur;
unsigned long long arrayDur;

NSMutableString * tapeResult = [NSMutableString stringWithString:@"{"];
NSMutableString * arrayResult = [NSMutableString stringWithString:@"{"];

NSString *string;

int iterations = 10000;

for (int i = 0; i <= iterations; i++)
{
    [tape appendObject:@""];
    [array addObject:@""];

    // CHTape
    start = mach_absolute_time();
    for (string in tape){}
    tapeDur = mach_absolute_time() - start;


    // NSArray
    start = mach_absolute_time();
    for (string in array){}
    arrayDur = mach_absolute_time() - start;


    // Results

    [tapeResult appendFormat:@"{%d, %lld}", i, (tapeDur/[tape count])];
    [arrayResult appendFormat:@"{%d, %lld}", i, (arrayDur/[array count])];

    if ( i != iterations)
    {
        [tapeResult appendString:@","];
        [arrayResult appendString:@","];
    }
}

[tapeResult appendString:@"}"];
[arrayResult appendString:@"}"];

NSString *plot = [NSString stringWithFormat:@"ListPlot[{%@, %@}]", tapeResult, arrayResult];
NSLog(@"%@", plot);

【问题讨论】:

  • NSMutableArray changes it's internal implementation as its size grows - 很可能它只是被实现为您正在使用的大小的原始 C 数组。
  • 它还针对迭代进行了高度优化,因为这是对数组最常用的操作之一。
  • 如果您想深入了解所有源代码,您可能还可以在open-sourced CFArray implementation 中找到所有答案。
  • 另见stackoverflow.com/questions/20724712/…countByEnumeratingWithState:... 实现不需要复制元素。
  • 您的 -countByEnumeratingWithState... 方法是否在启用 ARC 的情况下实现? NSArray 的实现关闭了 ARC,因此它避免了不必要的保留/释放调用。

标签: ios objective-c performance linked-list iteration


【解决方案1】:

通过在链接列表上强制关闭 ARC,相关文件的效率显着提高。它将访问时间从 ~70ns 减少到 ~14ns。虽然平均而言这仍然较慢,但 NSArray 平均而言仅慢了大约两倍,而不是慢了十倍。

虽然 ARC 可以使某些代码更快,但在迭代情况下会增加不必要的释放/保留调用。

感谢Greg Parker's 评论发现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 2015-12-10
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    相关资源
    最近更新 更多