NSOperation vs Grand Central Dispatch

465

Я изучаю параллельное программирование для iOS. До сих пор я читал о NSOperation/NSOperationQueue и GCD. Каковы причины использования NSOperationQueueснова GCDи наоборот?

Звучит как и то, GCDи другое, NSOperationQueueабстрагируясь от явного создания NSThreadsпользователя. Однако связь между этими двумя подходами мне не ясна, поэтому любые отзывы приветствуются!

Воскресение понедельник
источник
10
+1 за хороший вопрос - любопытно по результатам. Пока что я только что прочитал, что GCD можно легко распределить между ядрами процессора, что делает его «новым горячим дерьмом».
до
3
Некоторое связанное обсуждение может быть найдено в этом вопросе: Почему я должен выбрать GCD вместо NSOperation и блоки для приложений высокого уровня?
Брэд Ларсон
1
cocoacasts.com/…
Масих

Ответы:

517

GCDявляется низкоуровневым API на основе C, который позволяет очень просто использовать модель параллелизма на основе задач. NSOperationи NSOperationQueueклассы Objective C, которые делают подобную вещь. NSOperationбыл представлен первым, но по состоянию на 10.5 и iOS 2 , NSOperationQueueа друзья реализованы внутренне с помощью GCD.

В общем, вы должны использовать самый высокий уровень абстракции, который соответствует вашим потребностям. Это означает, что вы обычно должны использовать NSOperationQueueвместо GCD, если вам не нужно делать что-то, что NSOperationQueueне поддерживает.

Обратите внимание, что NSOperationQueueэто не «тупая» версия GCD; на самом деле, есть много вещей, которые вы можете сделать очень просто, NSOperationQueueкоторые требуют много работы с чистым GCD. (Примеры: очереди с ограниченной пропускной способностью, которые одновременно выполняют только N операций; устанавливают зависимости между операциями. Обе очень простые NSOperation, очень сложные GCD.) Apple проделала тяжелую работу по использованию GCD для создания очень приятного объектно-ориентированного API NSOperation. Воспользуйтесь их работой, если у вас нет причин не делать этого.

Предостережение : с другой стороны, если вам действительно нужно отправить блок, и вам не нужны какие-либо дополнительные функциональные возможности, то NSOperationQueueнет ничего плохого в использовании GCD. Просто убедитесь, что это правильный инструмент для работы.

Би Джей Гомер
источник
1
NSOperation, чтобы быть конкретным абстрактным классом.
Рошан
3
@ Sandy На самом деле все наоборот: GCD используется NSOperation (по крайней мере, в более поздних версиях iOS и OS X).
garrettmoon
1
@BJ Homer Мы можем добавить задачу в очередь последовательной отправки, чтобы получить зависимость. так просто, как очередь работы имеет преимущество перед этим
Радж Аггравал
3
@RajAggrawal Да, это работает ... но тогда вы застряли в последовательной очереди. NSOperation может выполнить «выполнить эту операцию после того, как будут выполнены остальные три, но одновременно со всеми другими происходящими вещами». Операционные зависимости могут даже существовать между операциями в разных очередях. Большинству людей это не нужно, но если вы сделаете это, NSOperation будет лучшим выбором.
Би Джей Гомер
369

В соответствии с моим ответом на связанный вопрос , я собираюсь не согласиться с BJ и предложить вам сначала взглянуть на GCD через NSOperation / NSOperationQueue, если последний не предоставляет то, что вам нужно, а GCD - нет.

До GCD я использовал много NSOperations / NSOperationQueues в своих приложениях для управления параллелизмом. Однако, так как я начал использовать GCD на регулярной основе, я почти полностью заменил NSOperations и NSOperationQueues на блоки и очереди отправки. Это произошло из-за того, что я использовал обе технологии на практике, и из профилирования, которое я использовал для них.

Во-первых, при использовании NSOperations и NSOperationQueues нетривиальные издержки. Это объекты Какао, и они должны быть выделены и освобождены. В написанном мною приложении iOS, которое визуализирует трехмерную сцену со скоростью 60 кадров в секунду, я использовал NSOperations для инкапсуляции каждого визуализированного кадра. Когда я рассказывал об этом, создание и разборка этих NSOperations составляли значительную часть циклов ЦП в работающем приложении и замедляли работу. Я заменил их простыми блоками и последовательной очередью GCD, и эти издержки исчезли, что привело к заметно лучшей производительности рендеринга. Это было не единственное место, где я заметил накладные расходы от использования NSOperations, и я видел это как на Mac, так и на iOS.

Во-вторых, существует элегантность для блочного кода отправки, который трудно сопоставить при использовании NSOperations. Это так невероятно удобно, чтобы обернуть несколько строк кода в блок и отправить его для выполнения в последовательную или параллельную очередь, где для создания настраиваемой NSOperation или NSInvocationOperation для этого требуется гораздо больше вспомогательного кода. Я знаю, что вы можете использовать NSBlockOperation, но вы можете отправлять что-то в GCD. Заключение этого кода в блоки в соответствии с соответствующей обработкой в ​​вашем приложении, на мой взгляд, приводит к лучшей организации кода, чем использование отдельных методов или пользовательских операций NSO, которые инкапсулируют эти задачи.

NSOperations и NSOperationQueues по-прежнему имеют очень хорошее применение. GCD не имеет реальной концепции зависимостей, где NSOperationQueues может создавать довольно сложные графы зависимостей. Я использую NSOperationQueues для этого в нескольких случаях.

В целом, хотя я обычно выступаю за использование самого высокого уровня абстракции, который выполняет задачу, это один из случаев, когда я спорю о низкоуровневом API GCD. Среди разработчиков iOS и Mac, с которыми я говорил об этом, подавляющее большинство предпочитают использовать GCD поверх NSOperations, если они не нацелены на версии ОС без поддержки этого (те, что до iOS 4.0 и Snow Leopard).

Брэд Ларсон
источник
20
Я только слегка не согласен; Я использую обычный GCD совсем немного. Но я думаю, что в этом ответе вы слишком сильно игнорируете NSBlockOperation. Все преимущества NSOperationQueue (зависимости, отладка и т. Д.) Применимы и к блочным операциям.
Би Джей Гомер
4
@BJHomer - Я думаю, что избегание NSBlockOperation - это скорее вопрос личных предпочтений в моем случае, хотя я вообще отошел от NSOperations, увидев, что накладные расходы от их использования затягивают пару приложений. Если я собираюсь использовать блоки, я склонен идти олл-ин на GCD, за редким исключением, когда мне нужна поддержка зависимостей.
Брэд Ларсон
1
+1, спасибо за этот анализ. Apple, кажется, поддерживает оба (как сессия WWDC 2012 по параллельному интерфейсу), так что это очень ценится.
orip
1
@VolureDarkAngel - GCD очень быстро обрабатывает такие отправки. Это не должно быть вашим узким местом в ситуации, как вы описываете, если только вы не скопируете кучу обновлений в очередь из-за медленного доступа к вводу / выводу или чего-то в этом роде. Это, вероятно, не тот случай, здесь.
Брэд Ларсон
1
@ asma22 - Распространены расчеты, которые можно выполнять по частям, но для окончательного расчета одного этапа могут потребоваться результаты нескольких предыдущих этапов. В этом случае вы можете сделать эту более позднюю операцию зависимой от более ранних операций, и планирование будет управляться таким образом, чтобы все они выполнялись до выполнения последней.
Брэд Ларсон
101

GCDявляется низкоуровневым C-API.
NSOperationи NSOperationQueueявляются классами Objective-C.
NSOperationQueueявляется объективной оберткой C над GCD. Если вы используете NSOperation, то вы неявно используете Grand Central Dispatch.

Преимущество GCD перед NSOperation:
i. Реализация
Для GCDреализации очень легкий
NSOperationQueue, сложный и тяжелый

Преимущества NSOperation перед GCD:

я. Control On Operation
вы можете приостановить, отменить, возобновитьNSOperation

II. Зависимости, которые
вы можете установить зависимость между двумя NSOperations
операциями, не будут запущены, пока все ее зависимости не вернут true для завершения.

III. State of Operation
может отслеживать состояние операции или очереди операций. готов, выполняется или закончен

внутривенно Максимальное количество операций,
вы можете указать максимальное количество операций в очереди, которые могут выполняться одновременно

Когда следует использовать Go GCDилиNSOperation
когда вам нужен больший контроль над очередью (все вышеупомянутое), NSOperation а также для простых случаев, когда вам нужно меньше накладных расходов (вы просто хотите выполнить некоторую работу «в фоновом режиме» с очень небольшой дополнительной работой).GCD

ссылка:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http : //nshipster.com/nsoperation/

Санграм Шиванкар
источник
Как уже было сказано, максимальное число операций может быть указано в NSOperationQueue. Тогда каково может быть максимальное количество операций (очередей отправки) в GCD? Предположим, у меня есть проект. Тогда сколько операций (очередей отправки) я могу сделать. или их максимальные пределы, которые мы можем сделать.
Рошан Сах
Это зависит от состояния системы. Подробная информация здесь: stackoverflow.com/questions/14995801/…
Санграм Шиванкар
Мы также можем отменить задание в GCD с помощью DispatchWorkItem, а также можем приостановить и возобновить его
Ankit garg
@Ankitgarg Вызов отмены в DispatchWorkItem остановит выполнение задач, если они еще не запущены, но не остановит выполнение того, что уже выполняется. и как вы приостанавливаете / возобновляете DispatchWorkItem ??
abhimuralidharan
34

Другой причиной, по которой NSOperation предпочтительнее GCD, является механизм отмены NSOperation. Например, приложение, такое как 500px, которое показывает десятки фотографий, использует NSOperation, мы можем отменить запросы невидимых ячеек изображения, когда мы прокручиваем представление таблицы или представление коллекции, это может значительно повысить производительность приложения и уменьшить объем памяти. GCD не может легко поддержать это.

Также с NSOperation KVO может быть возможным.

Вот статья из Eschaton, которую стоит прочитать.

evanchin
источник
4
Стоит отметить, что если то, что вы отменяете, это сетевая операция загрузки образа, то вам это не нужно NSOperation, так как NSURLSessionTask.cancelи NSURLSession.invalidateAndCancelпредоставляют эту функциональность. В общем, NSURLSessionпредоставляет некоторые функциональные возможности NSOperationQueue, а также NSURLSessionTaskпредоставляет некоторые функциональные возможностиNSOperation
algal
@algal Как объяснено здесь ( stackoverflow.com/questions/21918722/… ), кажется, что NSURLSession использует NSOperationQueue в качестве строительного блока.
Калан Наваратне
33

GCD действительно более низкого уровня, чем NSOperationQueue, его главное преимущество заключается в том, что его реализация очень легкая и ориентирована на алгоритмы и производительность без блокировок.

NSOperationQueue предоставляет средства, которые недоступны в GCD, но они имеют нетривиальную стоимость, реализация NSOperationQueue сложна и тяжела, включает в себя много блокировок и использует GCD изнутри только минимальным образом.

Если вам нужны средства, предоставляемые NSOperationQueue, во что бы то ни стало, используйте его, но если GCD достаточно для ваших нужд, я бы порекомендовал использовать его напрямую для повышения производительности, значительного снижения затрат на ЦП и энергопотребление и большей гибкости.

десять кубометров
источник
24

И NSQueueOperations, и GCD позволяют выполнять сложные вычислительные задачи в фоновом режиме в отдельных потоках, освобождая основную программу приложения UI.

Итак, основываясь на предыдущем посте, мы видим, что NSOperations имеет addDependency, чтобы вы могли последовательно ставить свои операции в очередь.

Но я также читал о последовательных очередях GCD, которые вы можете создавать для запуска своих операций в очереди с помощью dispatch_queue_create. Это позволит последовательно выполнять набор операций один за другим.

NSQueueOperation Преимущества перед GCD:

  1. Он позволяет добавить зависимость и позволяет удалить зависимость, поэтому для одной транзакции вы можете запускать последовательно с использованием зависимости, а для другой транзакции - одновременно, в то время как GCD не позволяет работать таким образом.

  2. Операцию легко отменить, если она находится в очереди, ее можно остановить, если она выполняется.

  3. Вы можете определить максимальное количество одновременных операций.

  4. Вы можете приостановить операцию, которую они находятся в очереди

  5. Вы можете найти сколько ожидающих операций в очереди.

Shashi3456643
источник
6

GCD очень прост в использовании - если вы хотите сделать что-то в фоновом режиме, все, что вам нужно сделать, это написать код и отправить его в фоновую очередь. Делать то же самое с NSOperation - это много дополнительной работы.

Преимущество NSOperation заключается в том, что (a) у вас есть реальный объект, на который вы можете отправлять сообщения, и (b) вы можете отменить NSOperation. Это не тривиально. Вам необходимо создать подкласс NSOperation, вы должны правильно написать свой код, чтобы отмена и правильное завершение задачи работали правильно. Так что для простых вещей вы используете GCD, а для более сложных вещей вы создаете подкласс NSOperation. (Существуют подклассы NSInvocationOperation и NSBlockOperation, но все, что они делают, легче сделать с помощью GCD, поэтому нет веских оснований для их использования).

gnasher729
источник
3

Ну, NSOperations - это просто API, созданный поверх Grand Central Dispatch. Поэтому, когда вы используете NSOperations, вы все еще используете Grand Central Dispatch. Просто NSOperations дает вам некоторые интересные функции, которые вам могут понравиться. Вы можете сделать некоторые операции зависимыми от других операций, изменить порядок очередей после добавления элементов и тому подобное. Фактически, ImageGrabber уже использует NSOperations и очереди операций! ASIHTTPRequest использует их под капотом, и вы можете настроить очередь операций, которую он использует, для другого поведения, если хотите. Так что вы должны использовать? Все, что имеет смысл для вашего приложения. Для этого приложения это довольно просто, поэтому мы просто использовали Grand Central Dispatch напрямую, без необходимости в необычных функциях NSOperation. Но если они нужны для вашего приложения, не стесняйтесь использовать его!

Анкул Гаур
источник