за допомогою dispatch_sync у Grand Central Dispatch


74

Хто-небудь може пояснити справді чіткими випадками використання, для чого призначена dispatch_syncin GCD? Я не можу зрозуміти, де і чому мені довелося б це використовувати.

Дякую!

Відповіді:


78

Ви використовуєте його, коли хочете виконати блок і чекати результатів.

Одним із прикладів цього є шаблон, коли ви використовуєте чергу відправлення замість блокування для синхронізації. Наприклад, припустимо, що у вас є загальний NSMutableArray a, доступ якого опосередкований чергою відправлення q. Фоновий потік може додаватися до масиву (асинхронно), тоді як ваш потік переднього плану витягує перший елемент (синхронно):


1
Я поставлю +1, оскільки це технічно правильно, хоча я не маю великої цінності робити сингл, dispatch_asyncза яким слідує a dispatch_syncв одній черзі. Однак цей самий шаблон корисний, коли ви хочете породити кілька одночасних завдань в іншій черзі, а потім чекати їх усіх.
kperryua

Дякую. Це починає мати сенс. Що робити, якщо я хочу запустити кілька паралельних потоків за допомогою dispatch_apply, які отримують доступ до одного ресурсу із взаємним виключенням. Як це зробити за допомогою GCD? Єдиний спосіб - це використовувати dispatch_async із послідовною чергою в моєму dispatch_apply? Чи є спосіб використовувати dispatch_sync?
Распутін Джонс,

@kperryua - вибачте, якщо приклад не був зрозумілим - ідея полягає в тому, що окремий потік робив би декілька dispatch_async в чергу
David Gelhar

@David Gelhar - Немає проблем. Просто згадую про інших, хто приходить шукати.
kperryua

9
Мені також подобається думати, що це схоже на використання -performSelector:onThread:withObject:waitUntilDone:або performSelectorOnMainThread:withObject:waitUntilDone:встановлення waitUntilDoneТАК.
Бред Ларсон

78

Спочатку зрозумій свого брата dispatch_async

Ви використовуєте dispatch_asyncдля створення нового потоку. Коли ви це зробите, поточний потік не зупиниться. Цей засіб //Do More Stuffможе бути виконаний раніше//Do something else фінішу

Що станеться, якщо ви хочете, щоб поточний потік зупинився?

Ви взагалі не використовуєте відправлення. Просто напишіть код нормально

Тепер скажіть, що хочете зробити щось за РІЗНОЮ ниткою, і все ж зачекайте, як ніби, і переконайтесь, що матеріали виконуються послідовно .

Є багато причин для цього. Наприклад, оновлення інтерфейсу здійснюється в основному потоці.

Ось де ви використовуєте dispatch_sync

Тут ви зробили //Do something //Do something elseі //Do More stuffзробили послідовно, хоча//Do something else це робиться з іншої нитки.

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

Отже, dispatch_sync використовується рідко. Але воно там. Я особисто ніколи цим не користувався. Чому б не попросити якийсь зразок коду чи проекту, який використовує dispatch_sync.


Це була чудова відповідь для мене, дякую. Прикладом використання dispatch_syncє інший процес асинхронізації для використання як зворотний виклик. Наприклад, performBlockметод NSManagedObjectContext Core Data може використовувати його в кінці блоку як зворотний виклик.
abc123

16
Як початківець GCD, я знайшов це речення оманливим: "Ви використовуєте dispatch_async для створення нового потоку". З того, що я досі розумів про GCD, виклик dispatch_async не обов'язково створює новий потік. Система, на мою думку, буде обробляти створення потоків або атрибуцію кожного завдання в черзі.
Aurelien Porte

Насправді я зараз цим користуюся багато. Я можу виконати код у фоновому потоці та dispatch_sync до основного потоку.
user4951

Це ВЕЛИКО - справді зрозумійте це зараз. Дякую!
darkheartfelt

1
Окрім очевидної невеликої помилки, зазначеної в коментарях, це пояснення дуже чітке та корисне, дякую!
Ixx

26

dispatch_sync семантично еквівалентний традиційному блокуванню мьютексу.

працює так само, як


2
Це справедливо для послідовної черги, але для одночасної черги ми повинні використовувати dispatch_barrier_async для операції запису та dispatch_sync для операції читання.
Параг Бафна

4

Девід Гелхар не сказав, що його приклад буде працювати лише тому, що він тихо створив послідовну чергу (передав NULL у dispatch_queue_create, що дорівнює DISPATCH_QUEUE_SERIAL).

Якщо ви хочете створити паралельну чергу (щоб отримати всю багатопотокову потужність), його код призведе до аварії через мутацію NSArray (addObject :) під час мутації (removeObjectAtIndex :) або навіть поганий доступ (діапазон NSArray за межами). У цьому випадку ми повинні використовувати бар’єр, щоб забезпечити ексклюзивний доступ до NSArray, поки обидва блоки працюють. Він не тільки виключає всі інші записи в NSArray під час роботи, але також виключає всі інші читання, роблячи модифікацію безпечною.

Приклад для одночасної черги повинен виглядати так:


3

Якщо вам потрібні деякі зразки практичного використання, подивіться на це моє питання:

Як вирішити цю тупикову ситуацію, яка трапляється випадково?

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

Мені потрібна dispatch_sync, оскільки для основного потоку потрібно виконати певний код, який відрізняється від потоку, де виконується кодування.

Отже, якщо ви хочете, щоб код 1. 1. Продовжуйте, як зазвичай. Ви не хочете турбуватися про умови перегонів. Ви хочете переконатися, що код заповнений перед тим, як рухатись далі. 2. Виконано на іншій нитці

використовувати dispatch_sync.

Якщо 1 порушено, використовуйте dispatch_async. Якщо 2 порушено, просто напишіть код, як зазвичай.

Поки що я роблю це лише один раз, а саме тоді, коли потрібно щось робити з основною ниткою.

Отже, ось код:


2

dispatch_sync в основному використовується всередині блоку dispatch_async для виконання деяких операцій з основним потоком (наприклад, оновлення ui).


0

Ось реалістичний приклад на півдорозі. У вас 2000 zip-файлів, які ви хочете аналізувати паралельно. Але бібліотека zip не захищена від потоків. Тому вся робота, яка стосується zip-бібліотеки, надходить у unzipQueueчергу. (Приклад наведено в Ruby, але всі виклики відображаються безпосередньо в бібліотеці C. "apply", наприклад, map to dispatch_apply (3) )


9
Використовуйте псевдокод, якщо хочете щось пояснити. Рубі та ін. Занадто специфічні та мають високий рівень.
Метт Мелтон,

-1

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

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

Приклад блоку:

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