NSOperation vs Grand Central Dispatch


465

Я дізнаюся про одночасне програмування для iOS. Поки я читав про NSOperation/NSOperationQueue і GCD. Які причини використання NSOperationQueueнад GCDі навпаки?

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


10
+1 за гарне запитання - цікаво про результати. Поки щойно я читав, що GCD легко пересилається по ядрах процесора, і це стає "новим гарячим лайном".
До

3
Деякі пов'язані з цим дискусії можна знайти в цьому запитанні: Чому я повинен вибрати GCD через NSOperation та блоки для додатків високого рівня?
Бред Ларсон

Відповіді:


517

GCDце API на основі низького рівня, який дозволяє дуже просто використовувати модель сумісності на основі завдань. 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. Скористайтеся їхньою роботою, якщо у вас немає причин цього не робити.

Caveat : З іншого боку, якщо вам дійсно просто потрібно відправити блок, і вам не потрібна додаткова функціональність, яка NSOperationQueueнадається, немає нічого поганого у використанні GCD. Просто будьте впевнені, що це правильний інструмент для роботи.


1
NSOperation бути конкретним абстрактним класом.
Рошан

3
@Sandy Насправді навпаки, GCD використовується NSOperation (принаймні, в пізніших версіях iOS та OS X).
garrettmoon

1
@BJ Homer Ми можемо додати завдання в черзі серійних відправлень, щоб досягти необхідності. тож просто уточнюйте, наскільки черга операцій має перевагу перед цим
Радж Аграваль

3
@RajAggrawal Так, це працює ... але тоді ви застрягли з послідовною чергою. NSOperation може зробити "виконати цю операцію після того, як будуть виконані інші три, але одночасно з усіма іншими речами, що відбуваються". Операційні залежності можуть існувати навіть між операціями на різних чергах. Більшість людей цього не потребуватиме, але якщо ви зробите це, кращий вибір буде NSOperation.
BJ Гомер

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 тоді. Обертання цього коду блоками, що відповідає їхній обробці у вашій програмі, на мою думку, призводить до кращої організації коду, ніж до використання окремих методів або спеціальних NSOperations, які інкапсулюють ці завдання.

NSOperations та NSOperationQueues все ще мають дуже гарне використання. GCD не має реальної концепції залежності, де NSOperationQueues може встановлювати досить складні графіки залежності. Для цього я використовую NSOperationQueues у кількох випадках.

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


20
Я лише м'яко не погоджуюся; Я використовую звичайний GCD зовсім небагато. Але я думаю, що ви занадто сильно знижуєте NSBlockOperation у цій відповіді. Усі переваги NSOperationQueue (залежності, налагодженість тощо) стосуються і блокових операцій.
BJ Гомер

4
@BJHomer - Я думаю, що уникнення NSBlockOperation - це більше питання особистого уподобання в моєму випадку, хоча я взагалі відмовився від NSOperations, побачивши, що накладні витрати від їх використання перетягнуть пару додатків. Якщо я збираюся використовувати блоки, я, як правило, використовую все включення на GCD, за рідкісним винятком, коли мені потрібна підтримка залежності.
Бред Ларсон

1
+1, спасибі за цей аналіз. Apple, схоже, виступає за обидва (як, наприклад, сесія WWDC 2012 щодо одночасного інтерфейсу), тому це дуже цінується.
orip

1
@VolureDarkAngel - GCD надзвичайно швидкий при обробці таких відправлень. Це не повинно бути вашим вузьким місцем у такій ситуації, як ви описуєте, якщо ви якимось чином не резервуєте купу оновлень у чергу через повільний доступ до вводу / виводу або щось подібне. Це, мабуть, тут не так.
Бред Ларсон

1
@ asma22 - Загальноприйняті розрахунки, які можна робити на шматки, але для остаточного обчислення одного етапу можуть знадобитися результати з декількох попередніх етапів. У такому випадку ви можете зробити так, щоб пізніші операції залежали від попередніх операцій, і планування буде керовано таким чином, що всі вони завершаться до запуску останньої.
Бред Ларсон

101

GCD- це API на основі низького рівня.
NSOperationі NSOperationQueueє класами Objective-C.
NSOperationQueueє об'єктивна C обгортка GCD. Якщо ви використовуєте NSOperation, ви неявно використовуєте Grand Central Dispatch.

Перевага GCD перед NSOperation:
i. реалізація
Для GCDреалізації дуже легкий
NSOperationQueue, складний і важкий

Переваги NSOperation в порівнянні з GCD:

i. Керування в роботі
Ви можете призупинити, скасувати, відновитиNSOperation

ii. Залежності, за допомогою
яких можна встановити залежність між двома NSOperations
операціями, не будуть запускатись, поки всі її залежності не повернуться до кінця.

iii. Держава Операція
може контролювати стан операції чи черги операцій. готовий, виконаний або закінчений

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

Коли потрібно йти GCDабоNSOperation
коли ви хочете більше контролювати чергу (все вищезгадане) використання NSOperation та для простих випадків, коли вам потрібно менше накладних витрат (ви просто хочете виконати якусь роботу "на задній план" з дуже малою додатковою роботою)GCD

ref:
https://cocoacasts.com/choosing-bet 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 / ...
Sangram Shivankar

Ми також можемо скасувати завдання в GCD, використовуючи DispatchWorkItem, і ми можемо також призупинити та відновити також
Ankit

@Ankitgarg Скасування виклику на DispatchWorkItem зупинить виконання завдань, якщо вони ще запущені, але не зупинить те, що вже виконується. і як ви призупиняєте / поновлюєте DispatchWorkItem ??
абхімуралідхаран

34

Ще однією причиною віддавати перевагу NSOperation над GCD є механізм скасування NSOperation. Наприклад, додаток на зразок 500 пікселів, який показує десятки фотографій, використовуючи NSOperation, ми можемо скасувати запити невидимих ​​комірок зображення, коли ми прокручуємо подання таблиці або перегляд колекції, це може значно покращити продуктивність додатків і зменшити слід пам’яті. GCD не може легко підтримати це.

Крім того, з NSOperation може бути можливим KVO.

Ось стаття з Есхатону, яку варто прочитати.


4
Варто зазначити, що якщо те, що ви скасовуєте, це мережева операція завантаження зображення, то NSOperationдля цього вам не потрібно , як NSURLSessionTask.cancelі NSURLSession.invalidateAndCancelнадайте цю функціональність. Загалом, NSURLSessionнадає деякі функціональні можливості NSOperationQueue, а також NSURLSessionTaskзабезпечує деякі функціональні можливостіNSOperation
algal

@algal Як пояснено тут ( stackoverflow.com/questions/21918722/… ), схоже, що NSURLSession використовує NSOperationQueue як будівельний блок.
kalan nawarathne

33

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

NSOperationQueue надає засоби, недоступні в GCD, але вони надходять за нетривіальної вартості, реалізація NSOperationQueue є складною та великою вагою, передбачає багато блокування та використовує GCD всередині лише в мінімальних масштабах.

Якщо вам потрібні засоби, що надаються NSOperationQueue, будь-якими способами користуйтеся нею, але якщо GCD достатній для ваших потреб, я рекомендую використовувати його безпосередньо для кращої продуктивності, значно меншої вартості процесора та потужності та більшої гнучкості.


24

І NSQueueOperations, і GCD дозволяють виконувати важкі завдання обчислення у фоновому режимі на окремих потоках, звільнивши основний протектор додатка інтерфейсу.

Ну, виходячи з попереднього допису, ми бачимо, що NSOperations має addDependency, так що ви можете чергувати свою операцію одна за одною послідовно.

Але я також читав про послідовні черги GCD, які ви можете створити запустити свої операції в черзі, використовуючи dispatch_queue_create. Це дозволить послідовно виконувати набір операцій.

Переваги NSQueueOperation щодо GCD:

  1. Це дозволяє додати залежність і дозволяє видалити залежність, тому для однієї транзакції можна запускати послідовно, використовуючи залежність, а для інших транзакцій виконуючись одночасно, поки GCD не дозволяє запускати цей спосіб.

  2. Скасувати операцію легко, якщо вона стоїть у черзі, її можна зупинити, якщо вона працює.

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

  4. Ви можете призупинити роботу, яка знаходиться в черзі

  5. Ви можете знайти, скільки операцій, що очікують, є у черзі.


6

GCD дуже простий у використанні - якщо ви хочете зробити щось у фоновому режимі, все, що вам потрібно зробити, - це написати код і відправити його по черзі фону. Зробити те ж саме з NSOperation - це багато додаткової роботи.

Перевага NSOperation полягає в тому, що (a) у вас є реальний об'єкт, на який ви можете відправляти повідомлення, і (b) у тому, що ви можете скасувати NSOperation. Це не банально. Вам потрібно підкласи NSOperation, ви повинні правильно записати свій код, щоб скасування та правильне виконання завдання обидва працювали правильно. Отже, для простих речей ви використовуєте GCD, а для більш складних речей створюєте підклас NSOperation. (Є підкласи NSInvocationOperation та NSBlockOperation, але все, що вони роблять, простіше зробити з GCD, тому немає вагомих причин використовувати їх).


3

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.