【问题标题】:Preferred way to make a mutable copy of a non-mutable object?制作非可变对象的可变副本的首选方法?
【发布时间】:2012-01-24 10:37:09
【问题描述】:

有 2 个选择(可能更多)。以 NSSet 为例:

NSMutableSet * mutableSet = [ NSMutableSet setWithSet:nonMutableSet ] ;

NSMutableSet * mutableSet = [ [ nonMutableSet mutableCopy ] autorelease ] ;

这两种实现有什么区别吗?一个“更有效率”吗? (其他例子是 NSArray/NSMutableArray 和 NSDictionary/NSMutableDictionary

【问题讨论】:

  • 好问题,我怀疑这可能会引起很多争论。
  • 如果您想帮大家一个忙,请对其进行基准测试并自己回答问题 :) 不过,我怀疑应该没有太大区别。
  • @fzwo 我想我可以做到。虽然这部分是编程哲学问题:)

标签: ios foundation


【解决方案1】:

基准测试很有趣! :)

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{ @autoreleasepool {
    NSMutableSet *masterSet = [NSMutableSet set];

    for (NSInteger i = 0; i < 100000; i++) {
        [masterSet addObject:[NSNumber numberWithInteger:i]];
    }

    clock_t start = clock();

    for (NSInteger i = 0; i < 100; i++) {
        @autoreleasepool {
            [NSMutableSet setWithSet:masterSet];
        }
    }

    NSLog(@"a: --- %lu", clock() - start);

    sleep(1);

    start = clock();

    for (NSInteger i = 0; i < 100; i++) {
        @autoreleasepool {
            [[masterSet mutableCopy] autorelease]; 
        }
    }

    NSLog(@"b: --- %lu", clock() - start);

    return 0;
} }

在我的机器 (10.7) 上,setWithSet: 比 -mutableCopy 慢约 3 倍(有人想在 iOS 5 上尝试吗?:))

现在的问题是:为什么?

-mutableCopy 大部分时间都花在 CFBasicHashCreateCopy() 中(请参阅CFBasicHash.m)。这似乎是直接复制哈希桶,没有重新哈希。

Running  Time   Self  Symbol Name
256.0ms  61.5%  0.0   -[NSObject mutableCopy]
256.0ms  61.5%  0.0     -[__NSCFSet mutableCopyWithZone:]
256.0ms  61.5%  0.0       CFSetCreateMutableCopy
255.0ms  61.2%  156.0       CFBasicHashCreateCopy
97.0ms   23.3%  44.0          __CFSetStandardRetainValue

-setWithSet 枚举集合的每个值,然后将其添加到新集合中。从 CFBasicHashAddValue 的实现(同样在 CFBasicHash.m 中)看来,它正在重新散列集合中的每个值。

Running    Time Self    Symbol Name
1605.0ms   86.0%    0.0     +[NSSet setWithSet:]
1605.0ms   86.0%    2.0       -[NSSet initWithSet:copyItems:]
1232.0ms   66.0%    68.0        -[__NSPlaceholderSet initWithObjects:count:]
1080.0ms   57.8%    299.0         CFBasicHashAddValue
324.0ms    17.3%    28.0        -[NSSet getObjects:count:]
272.0ms    14.5%    75.0          __CFBasicHashFastEnumeration

这种重新散列在 CFSet 级别是有意义的。 CFSet 在 callBacks 参数中采用 CFSetHashCallBack;因此,两个 CFNumber 的 CFSet 可以指定不同的散列例程。 Foundation 的 NSSet 在底层使用 CFSet,并有一个调用 -[NSObject hash] 的 CFSetHashCallBack 函数。 (虽然我猜苹果可以优化这种情况并避免当两个集合具有相同的哈希回调时重新哈希)。

请注意,此基准测试仅适用于 NSSet(属于 NSNumbers),其他集合类可能具有不同的性能特征。

【讨论】:

  • 我相信数组可以有不同的支持实现(在 NSArray 类集群的私有子类中),具体取决于项目数量等情况,这会进一步复杂化基准测试(但通常会提高性能)。
  • 是的!此外,集合中的对象数量也会产生影响。需要注意的是,对于使用上述基准的数组,-mutableCopy/-autorelease 看起来稍微较慢 这些东西经常调整 - 经常重做基准而不是做出假设是个好主意关于Foundation类的性能特点:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多