NSArray怎么会这么慢?

时间:2011-06-07 13:59:28

标签: objective-c optimization stl

我来自C ++ / STL世界,我想检查Objective-c容器与stl相比如何。

我想比较一个数字数组,但是向NSArray添加数字的唯一方法是使用NSNumber,这非常慢并且我的ram空了,所以我想我需要解除它们手动。但我不想测试副作用,所以我只是将[NSNull null]添加到数组中。

将10k个东西加入阵列1k次的结果:
NSArray - 0.923411秒
vector<int> - 0.129984秒

我认为它可能是分配和解除分配所以我将数组(imax在代码中)的数量设置为1,添加数量设置为10000000(jmax),但它甚至更慢
NSArray - 2.19859秒
vector<int> - 0.223471秒

编辑:
正如评论中所提到的,数组不断增加的大小可能是问题所以我使用NSArray arrayWithCapacityvector reserve也是imax。 before(!)(jmax = 1,NSArray = 10000000)。
vector<int> - 2.55942
#import <Foundation/Foundation.h> #include <vector> #include <iostream> #include <time.h> using namespace std; int main (int argc, const char * argv[]) { int imax = 1000; int jmax = 10000; NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; cout << "Vector insertions" << endl; clock_t start = clock(); for(int i = 0; i < imax; i++) { vector<int> *v = new vector<int>(); for(int j = 0; j < jmax; j++) { v->push_back(j); } delete v; } double interval = (clock() - start) / (double)CLOCKS_PER_SEC; cout << interval << " seconds" << endl; cout << "NSArray insertions" << endl; start = clock(); for(int i = 0; i < imax; i++) { NSMutableArray *v = [[NSMutableArray alloc] init]; for(int j = 0; j < jmax; j++) { [v addObject:[NSNull null]]; } [v dealloc]; } interval = (clock() - start) / (double)CLOCKS_PER_SEC; cout << interval << " seconds" << endl; [pool drain]; return 0; } - 0.19139
结束编辑

为什么这么慢?

我的参考代码:

{{1}}

5 个答案:

答案 0 :(得分:22)

@JeremyP提供了一个很好的链接和信息。总是看鱼。这里有一些关于吃饭时间的细分,以及你可能会做些什么。

首先,有许多调用objc_msgSend()进行动态调度。这些可以避免,你可以节省一些时间(虽然没有你想象的那么多。objc_msgSend()crazy optimized)。但是你可以通过跳过它来降低5%的折扣:

  IMP addObject = class_getMethodImplementation([NSMutableArray class], @selector(addObject:));
  NSNull *null = [NSNull null];

  start = clock();

  for(int i = 0; i < imax; i++)
  {
    NSMutableArray *v = [[NSMutableArray alloc] init];
    for(int j = 0; j < jmax; j++)
    {
      addObject(v, @selector(addObject:), null);
    }
    [v release];
  }

retain / release会耗费大量时间。您可以通过使用非保留NSNumber来避免这种情况(并在CFMutableArray中加上实数)。这将使附加时间约为vector的2倍。

  CFArrayCallBacks cb = {0};
  for(int i = 0; i < imax; i++)
  {
    CFMutableArrayRef v = CFArrayCreateMutable(NULL, 0, &cb);
    for(int j = 0; j < jmax; j++)
    {
      CFArrayAppendValue(v, &j);
    }
    CFRelease(v);
}

这个的最大成本是调用memmove()(或Mac上的可收集版本)。

男人,NSMutableArray肯定很慢。苹果怎么会这么蠢,对吧?我的意思是,真的......等等......我想知道NSMutableArray是否比vector做得更好?

尝试将这些行换成明显的对应部分:

 v->insert(v->begin(), j);

  NSNumber *num = [[NSNumber alloc] initWithInt:j];
  [v insertObject:num atIndex:0];
  [num release];

(是的,包括创建和发布NSNumber,而不只是使用NSNull。)

哦,你也可以尝试这个,看看NSMutableArrayCFMutableArray真的有多快:

  CFArrayInsertValueAtIndex(v, 0, &j);

在我的测试中,我得到了:

Vector insertions
7.83188 seconds
NSArray insertions
2.66572 seconds
Non-retaining
0.310126 seconds

答案 1 :(得分:9)

简短的回答:是的,NSArray确实比C ++的STL集合类慢一点。这与编译时与运行时行为,编译器的优化机会以及众多实现细节有很大关系。

(而且,正如Rob指出的那样,NSMutableArray针对随机插入进行了优化,并且表现优于C ++ ......)

真正的答案:

微基准测试对于优化面向用户的应用程序毫无用处。

使用微基准来做出实施决策是过早优化的定义。

您很难找到针对iOS或Mac OS X的Objective-C应用程序,其中CPU分析将显示在与NSArray相关的代码路径中花费的任何重要时间,但绝大多数应用程序使用NS *集合课程几乎都是专门的。

当然,有些情况下NS *的性能不可行,为此,你转向C ++ / STL。

这些都不是暗示您的问题无效。如果没有更多的上下文,很难说观察到的性能差异是否真的重要(但是,根据我的经验,几乎每次开发人员根据微基准提出问题时,都会被误导)。

哦 - 并阅读this as it gives a bit of insight into the implementation of *Array

答案 2 :(得分:5)

这是一个完全成熟的Objective-C对象,这意味着每次添加对象时都会产生开销,这是因为Cocoa的消息查找算法是实现正确动态绑定所必需的。

还有一点是,NSArrays不一定是内部结构化的连续指针集。对于非常大的数组,NSArray比C ++向量执行得更好(即具有更好的大O时间复杂度)。请仔细阅读有关该主题的权威Ridiculous Fish Blog

答案 3 :(得分:2)

至少部分时间用于反复增加NSArray的容量。最初将NSArray初始化为正确(或至少更好)的容量应该更快:

[NSMutableArray arrayWithCapacity:10000];

答案 4 :(得分:0)

#include <stdio.h>
#include <time.h>

int main (int argc, char **argv)
{
    int imax = 1000;
    int jmax = 10000;

    clock_t start = clock();

    for(int i = 0; i < imax; i++)
    {
        int array[jmax];
        for(int j = 0; j < jmax; j++)
            j[array] = 0;
    }

    double interval = (clock() - start) / (double)CLOCKS_PER_SEC;

    printf("%f\n", interval);

    return 0;
}

我的2GHz Core2Duo iMac输出(用LLVM编译):

0.000003