Последовательность выполнения пользовательской параллельной очереди iOS GCD

У меня есть вопрос относительно этой проблемы, Согласно документам Apple

Параллельный Одновременные очереди (также известные как тип глобальной очереди отправки) выполняют одну или несколько задач одновременно, , но задачи все еще запускаются в том порядке, в котором они были добавлены в очередь. Выполняемые в настоящее время задачи выполняются на отдельные потоки, управляемые очередью отправки. Точное количество задач, выполняемых в любой заданной точке, является переменным и зависит от системных условий. В iOS 5 и более поздних версиях вы можете создавать параллельные очереди отправки самостоятельно, указав DISPATCH_QUEUE_CONCURRENT в качестве типа очереди. Кроме того, для вашего приложения есть четыре предопределенные глобальные параллельные очереди. Дополнительные сведения о том, как получить глобальные параллельные очереди, см. В разделе Получение глобальных параллельных очередей отправки.

И я делаю тест, используя пример кода,

  dispatch_queue_t concurrentQueue;
    concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue",
                                                 DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(concurrentQueue, ^{
         NSLog(@"First job ");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"Second job");
    });

    dispatch_async(concurrentQueue, ^{
        NSLog(@"Third job ");
  });

Но результаты выглядят не так, как порядок их добавления, вот результаты,

2015-06-03 18:36:38.114 GooglyPuff[58461:1110680] First job 
2015-06-03 18:36:38.114 GooglyPuff[58461:1110682] Third job
2015-06-03 18:36:38.114 GooglyPuff[58461:1110679] Second job

Итак, мой вопрос: не должно быть Первый второй третий?

Любые советы приветствуются, и спасибо за вашу помощь.

+4
источник поделиться
2 ответа

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

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

+3
источник

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

    dispatch_async(concurrentQueue, ^{
         JobThatTakes_3_SecToExecute(); // Job 1 (3 seconds to execute)
    });

    dispatch_async(concurrentQueue, ^{
        JobThatTakes_2_SecToExecute(); // Job 2 (2 seconds to execute)
    });

    dispatch_async(concurrentQueue, ^{
        JobThatTakes_1_SecToExecute(); // Job 3 (1 second to execute)
    });

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

Измените dispatch_async на dispatch_sync в этом примере, и очередь займет около 6 секунд. Они выйдут в следующем порядке: Job 1, 2, затем 3. Это гарантирует, что ваши результаты появятся в том порядке, в котором вы хотели, но это займет гораздо больше времени.

Итак, вернемся к значению того, что означают документы с помощью "задач, все еще запущены в том порядке, в котором они были добавлены в очередь" для параллельных очередей. Это будет заметно, если ваша работа ограничена ресурсами. Скажем, вы ставите большую кучу задач с длительной продолжительностью в параллельной очереди на 2-процессорной машине. Маловероятно, что вы сможете одновременно выполнять десяток задач по привязке к процессору; некоторым придется ждать, пока другие бегут. Порядок, в который вы помещаете их в очередь, решит, кто будет запускаться дальше, когда ресурсы освобождаются. В вашем примере задачи имеют очень короткую продолжительность и включают блокировку консоли (как сказал Роб), поэтому накладные расходы на очереди/блокировки могут испортиться с вашими ожиданиями.

Другая (вероятно, более важная) причина, по которой порядок выполнения в параллельных очередях имеет значение, когда используются барьеры. Возможно, вам понадобится выполнить какую-то задачу каждый N других задач, в которых барьер будет полезен. Фиксированный порядок выполнения гарантирует, что барьер выполняется после выполнения N задач одновременно, при условии, что вы помещаете барьер в очередь в нужном месте.

+1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос