Результаты теста и исходный код приведены ниже (вы можете установить количество итераций в приложении). Время указывается в миллисекундах, и каждая запись является средним результатом выполнения теста 5-10 раз. Я обнаружил, что, как правило, с точностью до 2-3 значащих цифр, и после этого он будет меняться с каждым прогоном. Это дает погрешность менее 1%. Тест проводился на iPhone 3G, так как это целевая платформа, которая меня интересовала.
numberOfItems NSArray (ms) C Array (ms) Ratio
100 0.39 0.0025 156
191 0.61 0.0028 218
3,256 12.5 0.026 481
4,789 16 0.037 432
6,794 21 0.050 420
10,919 36 0.081 444
19,731 64 0.15 427
22,030 75 0.162 463
32,758 109 0.24 454
77,969 258 0.57 453
100,000 390 0.73 534
Классы, предоставляемые Cocoa для обработки наборов данных (NSDictionary, NSArray, NSSet и т. Д.), Предоставляют очень хороший интерфейс для управления информацией, не беспокоясь о бюрократии управления памятью, перераспределения и т. Д. Конечно, это действительно происходит хотя стоимость. Я думаю, совершенно очевидно, что использование NSArray для NSNumbers будет медленнее, чем для массива с плавающей запятой C для простых итераций, поэтому я решил провести несколько тестов, и результаты оказались довольно шокирующими! Я не ожидал, что это будет так плохо. Примечание: эти тесты проводятся на iPhone 3G, поскольку это целевая платформа, которая меня заинтересовала.
В этом тесте я делаю очень простое сравнение производительности произвольного доступа между C float * и NSArray из NSNumbers
Я создаю простой цикл для суммирования содержимого каждого массива и определения времени для него, используя mach_absolute_time (). NSMutableArray занимает в среднем в 400 раз больше времени !! (не на 400 процентов, а в 400 раз дольше! это на 40000% дольше!).
Заголовок:
// Array_Speed_TestViewController.h
// Тест скорости массива
// Создано Мехметом Актеном 05.02.2009.
// Авторские права MSA Visuals Ltd. 2009. Все права защищены.
#import <UIKit/UIKit.h>
@interface Array_Speed_TestViewController : UIViewController {
int numberOfItems; // number of items in array
float *cArray; // normal c array
NSMutableArray *nsArray; // ns array
double machTimerMillisMult; // multiplier to convert mach_absolute_time() to milliseconds
IBOutlet UISlider *sliderCount;
IBOutlet UILabel *labelCount;
IBOutlet UILabel *labelResults;
}
-(IBAction) doNSArray:(id)sender;
-(IBAction) doCArray:(id)sender;
-(IBAction) sliderChanged:(id)sender;
@end
Реализация:
// Array_Speed_TestViewController.m
// Тест скорости массива
// Создано Мехметом Актеном 05.02.2009.
// Copyright MSA Visuals Ltd. 2009. Все права защищены.
#import "Array_Speed_TestViewController.h"
#include <mach/mach.h>
#include <mach/mach_time.h>
@implementation Array_Speed_TestViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSLog(@"viewDidLoad");
[super viewDidLoad];
cArray = NULL;
nsArray = NULL;
// read initial slider value setup accordingly
[self sliderChanged:sliderCount];
// get mach timer unit size and calculater millisecond factor
mach_timebase_info_data_t info;
mach_timebase_info(&info);
machTimerMillisMult = (double)info.numer / ((double)info.denom * 1000000.0);
NSLog(@"machTimerMillisMult = %f", machTimerMillisMult);
}
// pass in results of mach_absolute_time()
// this converts to milliseconds and outputs to the label
-(void)displayResult:(uint64_t)duration {
double millis = duration * machTimerMillisMult;
NSLog(@"displayResult: %f milliseconds", millis);
NSString *str = [[NSString alloc] initWithFormat:@"%f milliseconds", millis];
[labelResults setText:str];
[str release];
}
// process using NSArray
-(IBAction) doNSArray:(id)sender {
NSLog(@"doNSArray: %@", sender);
uint64_t startTime = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += [[nsArray objectAtIndex:i] floatValue];
}
[self displayResult:mach_absolute_time() - startTime];
}
// process using C Array
-(IBAction) doCArray:(id)sender {
NSLog(@"doCArray: %@", sender);
uint64_t start = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += cArray[i];
}
[self displayResult:mach_absolute_time() - start];
}
// allocate NSArray and C Array
-(void) allocateArrays {
NSLog(@"allocateArrays");
// allocate c array
if(cArray) delete cArray;
cArray = new float[numberOfItems];
// allocate NSArray
[nsArray release];
nsArray = [[NSMutableArray alloc] initWithCapacity:numberOfItems];
// fill with random values
for(int i=0; i<numberOfItems; i++) {
// add number to c array
cArray[i] = random() * 1.0f/(RAND_MAX+1);
// add number to NSArray
NSNumber *number = [[NSNumber alloc] initWithFloat:cArray[i]];
[nsArray addObject:number];
[number release];
}
}
// callback for when slider is changed
-(IBAction) sliderChanged:(id)sender {
numberOfItems = sliderCount.value;
NSLog(@"sliderChanged: %@, %i", sender, numberOfItems);
NSString *str = [[NSString alloc] initWithFormat:@"%i items", numberOfItems];
[labelCount setText:str];
[str release];
[self allocateArrays];
}
//cleanup
- (void)dealloc {
[nsArray release];
if(cArray) delete cArray;
[super dealloc];
}
@end
От: memo.tv
////////////////////
Доступно с момента появления блоков, это позволяет перебирать массив с блоками. Его синтаксис не так хорош, как быстрое перечисление, но есть одна очень интересная особенность: параллельное перечисление. Если порядок перечисления не важен и задания могут выполняться параллельно без блокировки, это может обеспечить значительное ускорение в многоядерной системе. Подробнее об этом в разделе одновременного перечисления.
[myArray enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
[self doSomethingWith:object];
}];
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWith:object];
}];
///////////
NSFastEnumerator
Идея быстрого перечисления заключается в использовании быстрого доступа к массиву C для оптимизации итерации. Мало того, что он должен быть быстрее, чем традиционный NSEnumerator, но Objective-C 2.0 также обеспечивает очень краткий синтаксис.
id object;
for (object in myArray) {
[self doSomethingWith:object];
}
/////////////////
NSEnumerator
Это форма внешней итерации: [myArray objectEnumerator] возвращает объект. Этот объект имеет метод nextObject, который мы можем вызывать в цикле, пока он не вернет nil
NSEnumerator *enumerator = [myArray objectEnumerator];
id object;
while (object = [enumerator nextObject]) {
[self doSomethingWith:object];
}
/////////////////
objectAtIndex: перечисление
Использование цикла for, который увеличивает целое число, и запрос объекта с помощью [myArray objectAtIndex: index] является наиболее простой формой перечисления.
NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
[self doSomethingWith:[myArray objectAtIndex:index]];
}
//////////////
От: darkdust.net