Главная |

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

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

или даже

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

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

[self doStuff];

верно?

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

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

dispatch_async

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

dispatch_sync

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

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

Удачи.

Ответ 4

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

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

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

Ответ 5

Свифт 3, 4 и 5

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

DispatchQueue.main.async {
    // Your code here
}

Ответ 6

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