Подтвердить что ты не робот

Objective C - Какой самый быстрый и эффективный способ перечислить массив?

Изменить

Я прочитал некоторые статьи о блоках и быстром перечислении, GCD и т.п. @Bbum, который написал много статей по теме GCD и блоков, говорит, что методы перечисления блоков всегда бывают быстрыми или быстрыми, чем быстрые эквиваленты перечисления. Вы можете прочитать его рассуждения здесь.

Хотя это был увлекательный интеллектуальный разговор, я согласен с теми, кто сказал, что это действительно зависит от поставленной задачи.


У меня есть некоторые задачи для выполнения, и мне нужно, чтобы они выполнялись быстро, дешево и эффективно. Apple дает нам много вариантов того, как мы хотим перечислять массив, но я не уверен, что выбрать.

Быстрое перечисление

for (id obj in array)
{
    /* Do something with |obj|. */
}

Перечисление неконкурентных блоков

[array enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
    /* Do something with |obj|. */
}];

Параллельное перечисление блоков

[array enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
    /* Do something with |obj|. */
}];

Применить GCD

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_apply([array count], queue, ^(size_t idx) {
    id obj = [array objectAtIndex: idx];
    /* Do something with |obj|. */
});

GCD Async Apply

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^(void) {
    dispatch_apply([array count], queue, ^(size_t idx) {
        id obj = [array objectAtIndex: idx];
        /* Do something with |obj|. */
    });
});

Или возможно что-то с NSBlockOperation или NSOperationQueue?

TIA, Алекс.

4b9b3361

Ответ 1

Самый быстрый код - это код, который сначала выходит на рынок.

Серьезно - если у вас нет измеримой проблемы с производительностью, этот конкретный выбор не должен занимать больше времени, чем нужно, чтобы ответить, какой из этих шаблонов наиболее подходит для моего проекта?

Примечание. При обращении к проблеме производительности при переходе от последовательного к параллельному выполнению обычно возникают две проблемы; производительность и concurrency.

Ответ 2

Это действительно зависит от поставленной задачи.

Обработка нескольких итераций за один раз требует нерестовых потоков. Если логика в итерациях параллелизуема и занимает больше времени, чем потребовалось бы для создания потока, то используйте потоки. Кроме того, если у вас столько элементов в массиве, что потребуется меньше времени для создания потока, чем для того, чтобы пройти через весь массив, разделите свой массив на несколько частей и обработайте их параллельно.

В противном случае нерестами потоков для итерации по массиву являются накладные расходы. Даже если ОС позаботится об этом, вам все равно придется их порождать. Это требует времени и ресурсов и переключения контекста во время выполнения (в зависимости от количества доступных процессоров, загрузки, планировщика и т.д.).

Все сводится к тому, что нерест нового потока занимает больше времени, чем прогулка по всему массиву. Вы можете найти это, используя инструменты профилирования.

Ответ 3

Если вы смотрите видео WWDC "Скрытые разработки Gems в iOS7" (этот вопрос старше, чем предоставленное видео), вы увидите, что простые для циклов перечисления могут быть лучше реализованы с использованием GCD:

[array enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: ^(id obj, NSUInteger idx, BOOL *stop) { /* Do something with |obj|. */ }];

Несмотря на то, что это зависит от поставленной задачи, и программное обеспечение для доставки имеет наибольшее значение, есть определенно простые способы избежать проблем с производительностью, возникающих в связи с проблемой технического долга в будущем, когда ваше приложение начнет масштабироваться, Например, у вас может быть большой результат выборки сети. Из этого результата вам может потребоваться выполнить итерацию по выбранным объектам и обновить некоторую модель или серию моделей (а не модели основных данных, поскольку основные данные не являются потокобезопасными!) Дополнительные меры должны быть предприняты для работы с Core Data для нескольких потоков. глубокую тему, которую вы хотите исследовать, если вы планируете работать с основными данными из многопоточного сценария). Учитывая, что вы не выполняете обновления для пользовательского интерфейса (так как это не то, что вы хотели бы отключить от основного потока), вы можете использовать этот метод, чтобы в полной мере использовать аппаратное обеспечение вашего устройства. Вместо цикла for, использующего только одно ядро ​​за раз, он будет полностью использовать доступные ядра параллельно, что увеличивает производительность и, возможно, почти вдвое сократит время выполнения. Это не то, что вы хотите сделать, не задумываясь над массивом, который вы перечисляете, и задачами, которые вы выполняете в блоке, но пригоден для широкого круга случаев, если их использовать осторожно.