Objective c NSMutableDictionary比Java映射慢得多。。。为什么?

Objective c NSMutableDictionary比Java映射慢得多。。。为什么?,objective-c,performance,Objective C,Performance,下面的代码将简单的值持有者映射到一个对象,在Java中运行速度比使用XCode 7 beta3的Objective-C快15倍,“最快、积极的优化[-Ofast]”。在Java中,我可以每秒获得2800万次的查找,但在objc示例中只能获得大约1900万次。(我在这里发布了相应的Java代码,因为这是一个快速比较:) 这是我真实代码的简化版本,它肯定受到哈希查找时间的限制,并且表现出这种总体性能差异。在下面的测试中,我测试null值只是为了确保编译器不会优化查找,但在实际应用中,我在大多数情况下

下面的代码将简单的值持有者映射到一个对象,在Java中运行速度比使用XCode 7 beta3的Objective-C快15倍,“最快、积极的优化[-Ofast]”。在Java中,我可以每秒获得2800万次的查找,但在objc示例中只能获得大约1900万次。(我在这里发布了相应的Java代码,因为这是一个快速比较:)

这是我真实代码的简化版本,它肯定受到哈希查找时间的限制,并且表现出这种总体性能差异。在下面的测试中,我测试null值只是为了确保编译器不会优化查找,但在实际应用中,我在大多数情况下都会使用该值

当我查看仪器时,我看到很多时间都花在保留/释放、msgSend和一些我不理解的锁定调用上

任何关于这比Java慢10-15倍或任何解决方法的想法都将不胜感激。实际上,我可以实现一个完美的散列,如下图所示,这样如果我能找到一个,我就可以为iOS使用一个快速int对象字典

@interface MyKey : NSObject <NSCopying>
    @property int xi;
@end

@implementation MyKey
    - (NSUInteger)hash { return self.xi; }
    - (BOOL)isEqual:(id)object    { return ((MyKey *)object).xi == self.xi; }
    - (id)copyWithZone:(NSZone *)zone { return self; }

@end

    NSMutableDictionary *map = [NSMutableDictionary dictionaryWithCapacity:2501];
    NSObject *obj = [[NSObject alloc] init];

    int range = 2500;
    for (int x=0; x<range; x++) {
        MyKey *key = [[MyKey alloc] init];
        key.xi=x;
        [map setObject:obj forKey:key];
    }

    MyKey *key = [[MyKey alloc] init];
    int runs = 50;
    for (int run=0; run<runs; run++)
    {
        NSDate *start = [NSDate date];

        int reps = 10000;
        for(int rep=0; rep<reps; rep++)
        {
            for (int x=0; x<range; x++) {
                key.xi=x;
                if ( [map objectForKey:key] == nil ) { NSLog(@"missing key"); }
            }
        }

        NSLog(@"rate = %f", reps*range/[[NSDate date] timeIntervalSinceDate:start]);
    }
@接口MyKey:NSObject
@属性席;
@结束
@实现MyKey
-(NSUnThink)哈希{返回Self.Xi;}
-(BoL)相等:(ID)对象{Read((MyKy*)对象).X= = Self.席;
-(id)copyWithZone:(NSZone*)区域{return self;}
@结束
NSMutableDictionary*map=[NSMutableDictionary字典容量:2501];
NSObject*obj=[[NSObject alloc]init];
整数范围=2500;

对于(int x=0;x您可以像这样重新实现
-isEqual:
方法以避免属性访问器:

- (BOOL) isEqual:(id)other
{
    return _xi == ((MyKey*)other)->_xi;
}

如果您的
MyKey
类可能是子类,那么这将是不可接受的,但我从Java代码中看到,存在的类是
final

NSMutableDictionary的计算复杂性是下一个(来自CFDictionary.h文件):

这意味着,几乎所有的时候,访问/插入/删除的复杂性都应该是O(1)。对于Java
HashMap
,应该得到几乎相同的复杂性

根据研究,使用容量为:
方便的初始值设定项的
字典没有任何好处

若您使用整数作为键,可能可以用数组替换字典

在这篇文章中,他们解释了性能问题以及如何处理这些问题。
第一个解决方案是使用C++和STL容器,第二个是使用SWIFT,因为不同于Objto-C,它只在注释时是动态的。< /P>使用<代码> NStUs>代码>代替< MyKey > <代码>双倍性能,表明<代码> MyKey <代码>约占性能的1/2。de>可能不是最好的性能测试。但哈希和相等方法以及为测试创建关键对象(这是计时的一部分)都存在计时问题。我不想指出Objective-C NSMutableDictionary甚至接近Java实现的速度。但我对这种差异感到惊讶e、 你是对的,使用NSNumber更快,我不知道为什么。仅供参考,我使用可变键避免读取循环期间的任何内存分配。有趣的是,可变本质上是一个标志。NSNumber是专门处理的,如果整数落在某个范围内,则不会创建对象,只会移动数字并在其中一个lea中设置位st有效位。这是因为地址落在边界上,否则这些位将保留为0。请添加Java代码,否则很难判断。但是,请注意,Java代码第一次运行时,它被编译为高度优化的本机代码(通过JIT),因此速度应该非常快。这并不能解释1)为什么Java在这个基准测试中比ObjC快10-15倍,或者2)为什么Swift又慢了近2倍。1)在Java中,你有字节码和JVM。比较Java和Objective C/Swift的性能是毫无意义的。2) 测试取决于许多因素,如实现、编译器、优化级别等。根据这些因素,一切都可以快速完成。当然,比较这些因素是有意义的。尽管有JIT,Java还是被认为是世界上速度最慢的主流语言之一。Objective C和Swift都是静态编译的,并且具有强大的编译时优化功能。人们期望他们在这样一个紧凑的微基准中摧毁Java,但事实并非如此,在数量级上。为什么不,为什么优化器让我们如此失望,这些都是值得讨论的有趣问题。你的答案甚至没有触及表面。在我看来,使用ARC有一个巨大的内在惩罚,Swift的设计师建议我们依赖结构和值语义,这让他们有点手舞足蹈。但这使得这些语言难以在这些高性能应用程序中使用。Java在这里的“不公平”优势是,当使用固定的对象池时,引用它们是“免费的”。但是ARC(至少目前)没有办法知道它们是长寿命的,必须做所有这些额外的不必要的工作来引用它们。
The access time for a value in the dictionary is guaranteed to be at
worst O(N) for any implementation, current and future, but will
often be O(1) (constant time). Insertion or deletion operations
will typically be constant time as well, but are O(N*N) in the
worst case in some implementations. Access of values through a key
is faster than accessing values directly (if there are any such
operations). Dictionaries will tend to use significantly more memory
than a array with the same number of values.