iPhone - главная тема Grand Central Dispatch - PullRequest
145 голосов
/ 26 октября 2011

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

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

или даже

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

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

[self doStuff];

верно?

Интересно, что вы, ребята, думаете.

Ответы [ 6 ]

293 голосов
/ 26 октября 2011

Отправка блока в основную очередь обычно выполняется из фоновой очереди, чтобы указать, что некоторая фоновая обработка завершена, например,

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

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

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

  • фоновая обработка завершена -> обновить пользовательский интерфейс
  • блок данных, обрабатываемых в фоновой очереди -> сигнализировать главной очереди о начале следующего фрагмента
  • входящие сетевые данные в фоновой очереди -> сигнализировать основной очереди, что сообщение прибыло
  • и т. Д.

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

15 голосов
/ 11 апреля 2012

Отправка блоков в основную очередь из основного потока может быть полезной.Это дает основной очереди возможность обрабатывать другие блоки, которые были поставлены в очередь, так что вы не просто блокируете выполнение всего остального.

Например, вы можете написать по существу однопоточный сервер, который, тем не менее, обрабатывает много одновременных соединений,Пока ни один отдельный блок в очереди не займет слишком много времени, сервер будет реагировать на новые запросы.

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

11 голосов
/ 26 октября 2011

Надеюсь, я правильно понимаю ваш вопрос в том, что вас интересует разница между dispatch_async и dispatch_sync?

dispatch_async

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

dispatch_sync

будет синхронно отправлять блок в очередь.Это предотвратит дальнейшее выполнение оставшегося кода в методе до тех пор, пока не завершится выполнение блока.

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

Удачи

8 голосов
/ 16 февраля 2018

Swift 3, 4 и 5

Запуск кода в главном потоке

DispatchQueue.main.async {
    // Your code here
}
8 голосов
/ 10 июля 2014

Одним из мест, где это полезно, является деятельность с пользовательским интерфейсом, например, установка счетчика перед длительной операцией:

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

не будет работать, потому что вы блокируете основной поток во время вашей длинной вещи и не позволяете UIKitна самом деле запустить спиннер.

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

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

1 голос
/ 06 декабря 2015

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

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Он включен в качестве стандартной функции в моем репо, проверьте его: https://github.com/goktugyil/EZSwiftExtensions

...