Цель C - Какой самый быстрый и эффективный способ перечисления массива? - PullRequest
26 голосов
/ 01 июня 2011

Редактировать

Я прочитал некоторые статьи о блоках и быстром перечислении и 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 Apply

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, Алекс.

Ответы [ 3 ]

44 голосов
/ 01 июня 2011

Самый быстрый код - это код, который первым достигает рынка.

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

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

4 голосов
/ 01 июня 2011

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

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

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

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

2 голосов
/ 18 апреля 2014

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

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

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

...