Заказ печати Swift Async? - PullRequest
       47

Заказ печати Swift Async?

0 голосов
/ 10 октября 2018

Всегда ли печатается в порядке 1 5 2 4 3?

print("1")
DispatchQueue.main.async {
    print("2")
    DispatchQueue.main.async {
        print(3)
    }
    print("4")
}
print("5")

Я чувствую, что ответ - нет, но я не могу объяснить это и надеюсь, что кто-то сможет прояснить мое понимание.Спасибо!

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Это зависит от того, с какого потока вы запускаете операцию.

Если вы начинаете с основного, то вы получите 1, 5, 2, 4, 3

Если вы начинаете с фонового потока, то большинствов тот момент, когда вы получите тот же результат (1, 5, 2, 4, 3), однако это не гарантируется, так как ОС может в любой момент перевести фоновый поток в спящий режим, и если это произойдет прямо перед вызовом print(5), то 5будет напечатан последним.

Просто обратите внимание, что если код из вопроса является единственным в вашем приложении / игровой площадке, вы можете быть удивлены, столкнувшись с частичными отпечатками, как приложение / игровая площадказавершает работу, как только попадает в строку print(5), перед тем как получить возможность выполнить асинхронную диспетчеризацию.Чтобы обойти это, вы можете убедиться, что RunLoop.current.run() выполняется в главном потоке как последняя часть вашего кода.

Вот некоторые схемы, которые пытаются проиллюстрировать, что происходит в сценарии только для основного потокаи тот, где задействован фоновый поток:

enter image description here enter image description here

0 голосов
/ 10 октября 2018

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

Если это запускается из основной очереди, то значение 5 всегда будет между 1 и 2.

Вот почему:

Этот код запускается в основной очереди.1 печатается.Затем вы ставите другой блок в очередь для асинхронного запуска в основной очереди, чтобы этот блок запускался после завершения текущего блока, и основная очередь доходила до конца текущего цикла выполнения.Код продолжается до следующей строки, которая должна вывести 5. Текущий блок заканчивается, и запускается следующий блок в главной очереди.Это блок первого звонка на DispatchQueue.main.async.Когда этот блок выполняется, он печатает 2 (так что теперь у нас есть 1 5 2).Другой блок ставится в очередь в основной очереди, как и последний.Текущий блок продолжается и печатает 4 (так что теперь у нас есть 1 5 2 4).Блок заканчивается и запускается следующий блок в главной очереди.Это последний блок, который мы добавили.Этот блок запускается, и он печатает 3, давая окончательный результат 1 5 2 4 3.

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

И вот почему:

Этот код начинается в фоновой очереди.1 печатается.Затем вы ставите в очередь другой блок для асинхронного запуска в основной очереди, чтобы этот блок запускался после завершения текущего цикла выполнения основной очереди.Код продолжается до следующей строки, которая должна вывести 5. Текущий блок заканчивается.Блок, добавленный в основную очередь, запускается параллельно фоновой очереди.В зависимости от времени запуска блока, добавленного в основную очередь, по отношению к оставшемуся коду в фоновой очереди, вывод print("5") может смешиваться с отпечатками из главной очереди.Вот почему 5 может появиться в любом месте после 1 при запуске из фона.

Но простой код в вопросе, скорее всего, всегда даст 1 5 2 4 3, даже если он запущен в фоновом режиме, потому что код таккороткий и занимает так мало времени.

Вот некоторый код, который помещает 5 в другом месте:

func asyncTest() {
    print("1")
    DispatchQueue.main.async {
        print("2")
        DispatchQueue.main.async {
            print(3)
        }
        print("4")
    }

    for _ in 0...1000 {
    }

    print("5")
}

DispatchQueue.global(qos: .background).async {
    asyncTest()
}

Существование цикла заставляет 5 занять немного больше времени, прежде чем появится, что позволяетОсновная очередь для выполнения до того, как будет напечатано 5.Без цикла фоновый поток выполняется слишком быстро, поэтому 5 появляется перед 2.

Если вы запускаете этот тест на игровой площадке, добавьте:

PlaygroundPage.current.needsIndefiniteExecution = true

в верхнюю часть игровой площадки (простопосле импорта).Вам также понадобится:

import PlaygroundSupport
...