我用全新的 Xcode 6 性能测试 (Objective-C) 和下面的测试用例测试了这个问题。我得到以下结果表明带有标志NSEnumerationConcurrent的enumerationBlock是大型数组的最快过滤方法:
testPerformancePredicateWithFormat - measured [Time, seconds] average: 0.189
testPerformancePredicateWithBlock - measured [Time, seconds] average: 0.093
testPerformanceEnumerationBlock - measured [Time, seconds] average: 0.092
testPerformanceIndexesOfObjectsPassingTest - measured [Time, seconds] average: 0.082
testPerformanceFastEnumeration - measured [Time, seconds] average: 0.068
testPerformanceEnumerationConcurrent - measured [Time, seconds] average: 0.036
这里是测试:
#import <XCTest/XCTest.h>
@interface TestPMTests : XCTestCase
@property(nonatomic, copy)NSArray *largeListOfDictionaries;
@end
@implementation TestPMTests
- (void)setUp {
[super setUp];
self.largeListOfDictionaries = [NSMutableArray array];
// Initialize a large array with ~ 300.000 entries as Dictionaries of at least one key value pair {"id":"<any id>"}
}
- (void)testPerformancePredicateWithFormat {
NSString *ID = @"204440e5-4069-48e8-a405-88882a5ba27e";
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF.id == %@", ID];
[self measureBlock:^{
NSArray *filtered = [self.largeListOfDictionaries filteredArrayUsingPredicate:pred];
NSLog(@"Count: %d", filtered.count);
}];
}
- (void)testPerformancePredicateWithBlock {
NSString *ID = @"204440e5-4069-48e8-a405-88882a5ba27e";
NSString *kID = @"id";
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(NSDictionary *d, NSDictionary *bindings) {
return [d[kID] isEqualToString:ID];
}];
[self measureBlock:^{
NSArray *filtered = [self.largeListOfDictionaries filteredArrayUsingPredicate:pred];
NSLog(@"Count: %d", filtered.count);
}];
}
- (void)testPerformanceIndexesOfObjectsPassingTest {
NSString *ID = @"204440e5-4069-48e8-a405-88882a5ba27e";
NSString *kID = @"id";
[self measureBlock:^{
NSIndexSet *matchingIndexes = [self.largeListOfDictionaries indexesOfObjectsPassingTest:^BOOL(NSDictionary *d, NSUInteger idx, BOOL *stop) {
return [d[kID] isEqualToString:ID];
}];
NSArray *filtered = [self.largeListOfDictionaries objectsAtIndexes:matchingIndexes];
NSLog(@"Count: %d", filtered.count);
}];
}
- (void)testPerformanceFastEnumeration {
NSString *ID = @"204440e5-4069-48e8-a405-88882a5ba27e";
NSString *kID = @"id";
[self measureBlock:^{
NSMutableArray *filtered = [NSMutableArray array];
for (NSDictionary *d in self.largeListOfDictionaries) {
if ([d[kID] isEqualToString:ID]) {
[filtered addObject:d];
}
}
NSLog(@"Count: %d", filtered.count);
}];
}
- (void)testPerformanceEnumerationBlock {
NSString *ID = @"204440e5-4069-48e8-a405-88882a5ba27e";
NSString *kID = @"id";
[self measureBlock:^{
NSMutableArray *filtered = [NSMutableArray array];
[self.largeListOfDictionaries enumerateObjectsUsingBlock:^(NSDictionary *d, NSUInteger idx, BOOL *stop) {
if ([d[kID] isEqualToString:ID]) {
[filtered addObject:d];
}
}];
NSLog(@"Count: %d", filtered.count);
}];
}
- (void)testPerformanceEnumerationConcurrent {
NSString *ID = @"204440e5-4069-48e8-a405-88882a5ba27e";
NSString *kID = @"id";
[self measureBlock:^{
NSMutableArray *filtered = [NSMutableArray array];
[self.largeListOfDictionaries enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSDictionary *d, NSUInteger idx, BOOL *stop) {
if ([d[kID] isEqualToString:ID]) {
[filtered addObject:d];
}
}];
NSLog(@"Count: %d", filtered.count);
}];
}
更新
我在-testPerformanceEnumerationConcurrent中更改了以下内容:
dispatch_sync(queue, ^{
[filtered addObject:d];
});
并发版本的结果仍然优于所有其他测试。
-[TestPMTests testPerformancePredicateWithFormat average: 0.134
-[TestPMTests testPerformancePredicateWithBlock] average: 0.079
-[TestPMTests testPerformanceEnumerationBlock] average: 0.079
-[TestPMTests testPerformanceIndexesOfObjectsPassingTest] average: 0.068
-[TestPMTests testPerformanceFastEnumeration] average: 0.054
-[TestPMTests testPerformanceEnumerationConcurrent] average: 0.029