dispatch_queue_t - это последовательная очередь, тогда почему она вообще существует в многозадачной концепции?

Я новичок в разработке для iPhone и прохожу концепцию GCD для многопоточности.

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

Например, я хочу сделать 2 задачи. Задача A и Задача B. Я создаю одну последовательную очередь для выполнения обеих этих задач. Я делаю это в основной очереди. Вот код, который я делаю:

dispatch_queue_t my_serial_queue = dispatch_queue_create("queue_identifier", 0);

    dispatch_sync(my_serial_queue, ^{
        NSLog(@"Task 1");
    });

    dispatch_sync(my_serial_queue, ^{
        NSLog(@"Task 2");
    });

Теперь, согласно правилу, обе задачи будут выполняться последовательно, так как это последовательная очередь, т.е. сначала выполняется задача A, а затем, после того как задача A будет завершена, будет выполнена задача B. И также это дает мне тот же вывод в журнале.

Итак, мой вопрос: что если я хочу выполнить обе задачи одновременно? Если ответом на этот вопрос является создание другой последовательной очереди для Задачи B, тогда код должен быть структурирован следующим образом:

dispatch_queue_t my_serial_queue_1 = dispatch_queue_create("queue_identifier_1", 0);
dispatch_queue_t my_serial_queue_2 = dispatch_queue_create("queue_identifier_2", 0);


    dispatch_sync(my_serial_queue_1, ^{
        NSLog(@"Task 1");
    });

    dispatch_sync(my_serial_queue_2, ^{
        NSLog(@"Task 2");
    });

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

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

2 ответа

Решение

Ваша путаница почти полностью связана с тем, что вы используете dispatch_sync. dispatch_sync - это не инструмент для одновременного выполнения, а инструмент для временного ограничения его безопасности.

Как только вы используете dispatch_async, вы можете получить параллелизм, имея более одной очереди или используя параллельные очереди. Цель использования последовательных очередей в этом контексте состоит в том, чтобы контролировать, какая работа выполняется одновременно.

Рассмотрим следующий очень глупый пример:

__block void *shared = NULL;
for (;;) {
    dispatch_async(aConcurrentDispatchQueue, ^{
        shared = malloc(128);
        free(shared);
    }
}

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

Подводя итог:

  • Когда работа в ваших блоках действительно независима, поточно-ориентирована и чисто вычислительна, продолжайте и используйте dispatch_async для параллельной очереди
  • Если у вас есть логически независимые задачи, каждая из которых состоит из нескольких связанных блоков, используйте последовательную очередь для каждой задачи
  • Когда у вас есть работа, которая обращается к общему изменяемому состоянию, выполняйте эти обращения в блоки ed dispatch_sync() в последовательной очереди, а остальную часть работы - в параллельной очереди.
  • Когда вам нужно выполнить работу, связанную с пользовательским интерфейсом, отправьте dispatch_async или dispatch_sync в основную очередь, в зависимости от того, нужно ли вам ждать его завершения или нет

'dispatch_queue_t' ничего не создает. dispatch_queue_t - очередь отправки, последовательная или одновременная.

dispatch_queue_create имеет два параметра. Второй параметр определяет, является ли созданная им очередь последовательной или параллельной. Но обычно вы не создаете параллельные очереди самостоятельно, а используете одну из трех существующих параллельных очередей.

dispatch_sync отправляет блок в очередь и ожидает его завершения. Должно быть очевидно, что это очень ограничивает параллелизм. Вы должны почти всегда использовать dispatch_async.

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

Поэтому для максимального использования процессоров используйте dispatch_async в параллельной очереди. И нет необходимости создавать более одной параллельной очереди. Это одновременно. Он может запускать любое количество блоков одновременно.

Другие вопросы по тегам