iPhone - главный поток Grand Central Dispatch

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

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

или даже

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

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

[self doStuff];

Правильно?

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


person Duck    schedule 26.10.2011    source источник
comment
Кстати, добавление основной очереди в dispatch_sync приведет к тупиковой ситуации.   -  person Brooks Hanes    schedule 12.12.2013
comment
Просто прочтите это в документации: в отличие от dispatch_async, [dispatch_sync] не возвращается, пока блок не будет завершен. Вызов этой функции и нацеливание на текущую очередь приводит к тупиковой ситуации ... Но, возможно, я неправильно это читаю ... (текущая очередь не означает основной поток). Пожалуйста, поправьте, если я ошибаюсь.   -  person Brooks Hanes    schedule 13.12.2013
comment
@BrooksHanes - не всегда правда. Это приведет к тупиковой ситуации, если вы уже находитесь в основном потоке. В противном случае не было бы тупика. См. здесь   -  person Honey    schedule 28.12.2016


Ответы (6)


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

- (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.

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

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

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

person Robin Summerhill    schedule 26.10.2011
comment
Ах я вижу. Так что я прав. В этом нет никаких преимуществ, если вы уже находитесь в основной очереди, просто если вы находитесь в другой очереди и хотите обновить пользовательский интерфейс. Спасибо. - person Duck; 26.10.2011
comment
Только что отредактировал свой ответ, чтобы поговорить о том, почему не очень полезно делать это из основной очереди. - person Robin Summerhill; 26.10.2011
comment
Кроме того, я думаю, что в iOS 4 есть ошибка (возможно, она исчезла в iOS 5), когда dispatch_sync в основную очередь из основного потока просто вызывает зависание, поэтому я бы полностью этого не делал. - person joerick; 27.10.2011
comment
Это не ошибка, это ожидаемое поведение. По общему признанию, это не очень полезное поведение, но вам всегда нужно помнить о взаимоблокировках при использовании dispatch_sync. Вы не можете ожидать, что система будет постоянно защищать вас от ошибок программиста. - person Robin Summerhill; 27.10.2011
comment
Что здесь за backgroundQueue? Как создать объект backgroundQueue - person Nilesh Tupe; 11.08.2012
comment
@NileshTupe, просто проверьте обновленный ответ, пожалуйста !, кстати, Робин уже описал его великолепно! +1 за это. - person swiftBoy; 21.02.2013
comment
я что-то здесь не понимаю .. так что первый вызов фоновой очереди инициирует эти длительные вычисления. Но поскольку он вызывается асинхронно, не означает ли это, что вложенный вызов диспетчеризации в основной очереди может начаться до завершения расчета? - person MikeG; 29.01.2016
comment
В вашем ответе, где обсуждали, что такое dispatch_sync (dispatch_get_main_queue () и где его следует или не следует использовать? Вы писали только о async типе ... - person Honey; 28.12.2016

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

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

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

person bames53    schedule 11.04.2012

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

dispatch_async

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

dispatch_sync

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

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

Удачи

person timthetoolman    schedule 26.10.2011
comment
спасибо, но я спрашиваю о преимуществах отправки чего-либо в основную очередь, находясь в основной очереди. - person Duck; 26.10.2011

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

- (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];
    });
}

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

person weaselfloss1    schedule 10.07.2014
comment
@Jerceratops да, но позволяет завершить текущий цикл выполнения. - person Dan Rosenstark; 24.11.2015
comment
Да, но все равно ужасно. Он по-прежнему блокирует пользовательский интерфейс. Я могу нажать еще одну кнопку сразу после этой. Или попробуйте прокрутить. (сделать что-то продолжительное) не должно происходить в основном потоке, и dispatch_async, позволяющий завершить нажатие кнопки, не является приемлемым решением. - person Jerceratops; 25.11.2015

Swift 3, 4 и 5

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

DispatchQueue.main.async {
    // Your code here
}
person Niall Kiddle    schedule 16.02.2018

Асинхронный означает асинхронный, и вы должны использовать его большую часть времени. Вы никогда не должны вызывать синхронизацию в основном потоке, потому что это заблокирует ваш пользовательский интерфейс до тех пор, пока задача не будет завершена. Вот лучший способ сделать это в 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

person Esqarrouth    schedule 06.12.2015