2017-02-03 2 views
1

Я инженер Android, пытающийся перенести некоторый код iOS, который использует 5 очередей отправки SERIAL. Я хочу убедиться, что я правильно думаю о вещах.Понимание dispatch_queues и синхронной/асинхронной отправки

  • dispatch_sync к серийному очереди, в основном, с использованием очереди, как синхронизированный queue- только один поток может получить доступ к нему, и блок, который запускается на выполнение можно рассматривать как критическую область. Это происходит сразу на токе его резьбового эквивалент

    get_semaphore() 
    queue.pop() 
    do_block() 
    release_semaphore() 
    
  • dispatch_async к последовательному queue- выполняет блок в другом потоке и сразу позволяет текущий возврат потока. Однако, поскольку он представляет собой очередную очередность, обещает, что только один из этих асинхронных потоков будет выполняться одновременно (следующий вызов dispatch_async будет ждать завершения всех остальных потоков). Этот блок можно также рассматривать как критическую область, но он будет происходить в другом потоке. Итак, тот же код, что и выше, но он сначала передан в рабочий поток.

Я в любом случае, или я правильно понял его?

ответ

1

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

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

Во-вторых, когда вы обсуждаете dispatch_sync, вы говорите что-то об этом «немедленно». Но это никоим образом не гарантировано, чтобы быть незамедлительным. Если нить выполняет dispatch_sync в какой-то последовательной очереди, то этот поток будет блокироваться до тех пор, пока (а) не будет выполнен какой-либо текущий блок в завершении последовательной очереди; (b) любые другие блоки в очереди для выполнения этой очереди и завершения этой очереди; и (c), очевидно, блок, который сам поток отправил, запускается и завершается.

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


Теперь Ваш вопрос говорит о «критической области», к которой я предполагаю, что вы говорите о каком-то немного кода, для того, чтобы обеспечить безопасность потоков или по какой другой причине, как это, должно быть синхронизированы. Таким образом, при запуске этого кода, который будет синхронизироваться, единственный вопрос: re dispatch_sync vs dispatch_async - это то, должен ли текущий поток ждать.Например, общий шаблон состоит в том, что можно записать dispatch_async в какую-либо модель (потому что нет необходимости ждать обновления модели перед продолжением), но dispatch_sync читает с некоторой модели (потому что вы, очевидно, не хотите продолжать пока не будет получено значение read).

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

+0

Критическая область - другое имя для критического раздела: https://en.wikipedia.org/wiki/Critical_section –

+0

Да, это то, что, как я думал, вы имели в виду. В iOS мы говорим о том, что нужно «синхронизировать». См. [Руководство по программированию потоков: синхронизация] (https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW1). Но это предшествует GCD, о котором говорится в [Руководстве по программированию параллелизма: устранение кода на основе блокировки] (https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/ThreadMigration/ThreadMigration.html#//apple_ref/DOC/UID/TP40008091-CH105-SW3). – Rob

+0

Да. Таким образом, я был немного неряшлив, говоря о вещах немедленно, но у меня было то, что он делал правильно. К счастью, я могу упростить до 1 очереди сообщений для реализации Android, не имея архитектуры, построенной вокруг основных уведомлений о данных, что упрощает работу. –

1

Чтобы выбрать nits, dispatch_sync не обязательно запускает код в текущем потоке, но если он этого не делает, он по-прежнему блокирует текущий поток, пока задача не завершится. Различие потенциально важно только в том случае, если вы полагаетесь на идентификаторы потоков или локальное хранилище потоков.

Но в остальном, да, если я не пропустил что-то тонкое.

+0

Полезно знать. Пересмотренный ответ. – dgatwood