Вы задаете правильные вопросы, но я думаю, что вы немного запутались (в основном из-за не очень четких сообщений по этой теме в Интернете).
Параллельный / последовательный
Давайте посмотрим, как можно создать новую очередь отправки:
let serialQueue = DispatchQueue(label: label)
Если вы не укажете какой-либо другой дополнительный параметр, эта очередь будет вести себя как последовательная очередь: это означает, что каждый блок, отправленный в эту очередь (синхронизация или асинхронность, не имеет значения), будет выполняться отдельно, без возможности для других блоков для одновременного выполнения в той же очереди.
Это не означает, что что-то еще остановлено, это просто означает, что если что-то еще отправлено в той же очереди, оно будет ждать завершения первого блока, прежде чем начинать его выполнение. Другие потоки и очереди по-прежнему будут работать сами по себе.
Однако вы можете создать параллельную очередь, которая не будет ограничивать эти блоки кода таким образом, и вместо этого, если случится так, что в той же очереди одновременно будет отправлено больше блоков кода, она выполнит их в в одно и то же время (в разных потоках)
let concurrentQueue = DispatchQueue(label: label,
qos: .background,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: .global())
Итак, вам просто нужно передать атрибут concurrent
в очередь, и он больше не будет последовательным.
(Я не буду говорить о других параметрах, поскольку они не рассматриваются в этом конкретном вопросе, и, я думаю, вы можете прочитать о них в другом сообщении SO, указанном в комментарии, или, если этого недостаточно, можно задать другой вопрос)
Если вы хотите больше узнать о параллельных очередях, (иначе: пропустите, если вас не интересуют параллельные очереди)
Вы можете спросить: когда мне вообще нужна параллельная очередь?
Ну, например, давайте подумаем о сценарии использования, в котором вы хотите синхронизировать READS на общем ресурсе: поскольку чтения могут выполняться одновременно без проблем, вы можете использовать для этого параллельную очередь.
Но что, если вы хотите писать на этом общем ресурсе? ну, в этом случае запись должна действовать как «барьер», и во время выполнения этой записи никакая другая запись и никакое чтение не могут работать с этим ресурсом одновременно. Чтобы добиться такого поведения, быстрый код должен выглядеть примерно так:
concurrentQueue.async(flags: .barrier, execute: { /*your barriered block*/ })
Другими словами, вы можете временно заставить параллельную очередь работать как последовательную очередь, если вам это нужно.
Еще раз, различие параллельных / последовательных операций действительно только для блоков, отправленных в ту же очередь, оно не имеет ничего общего с другой параллельной или последовательной работой, которая может выполняться в другом потоке / очереди.
СИНХРОНИЗАЦИЯ / АСИНХРОНИЗАЦИЯ
Это совершенно другая проблема, практически не имеющая отношения к предыдущей.
Эти два способа отправки некоторого блока кода относятся к текущему потоку / очереди, в которой вы находитесь во время вызова диспетчеризации. Этот вызов диспетчеризации блокирует (в случае синхронизации) или не блокирует (асинхронно) выполнение этого потока / очереди при выполнении кода, который вы отправляете в другую очередь.
Итак, скажем, я выполняю метод, и в этом методе я отправляю что-то асинхронно в какую-то другую очередь (я использую основную очередь, но это может быть любая очередь):
func someMethod() {
var aString = "1"
DispatchQueue.main.async {
aString = "2"
}
print(aString)
}
Что происходит, так это то, что этот блок кода отправляется в другую очередь и может выполняться последовательно или одновременно в этой очереди, но это не имеет никакого отношения к тому, что происходит в текущей очереди (которая является той, в которой вызывается someMethod).
Что происходит в текущей очереди, так это то, что код продолжит выполнение и не будет ждать завершения этого блока перед печатью этой переменной. Это означает, что, скорее всего, вы увидите, что он печатает 1, а не 2. (точнее, вы не можете знать, что произойдет первым).
Если вместо этого вы отправите его синхронизацию, вы ВСЕГДА напечатали бы 2 вместо 1, потому что текущая очередь ожидала бы завершения этого блока кода, прежде чем продолжить его выполнение.
Итак, это напечатает 2:
func someMethod() {
var aString = "1"
DispatchQueue.main.sync {
aString = "2"
}
print(aString)
}
Но означает ли это, что очередь, в которой вызывается someMethod, фактически остановлена?
Ну, это зависит от текущей очереди:
- Если серийный, то да. Все блоки, ранее отправленные в эту очередь или которые будут отправлены в эту очередь, должны будут дождаться завершения этого блока.
- Если это одновременно, то нет. Все параллельные блоки продолжат свое выполнение, только этот конкретный блок выполнения будет заблокирован, ожидая, пока этот вызов диспетчеризации завершит свою работу. Конечно, если мы находимся в случае запрета, то это похоже на последовательные очереди.
Что произойдет, если currentQueue и очередь, в которую мы отправляем, совпадают?
Предполагая, что мы находимся в последовательных очередях (что, я думаю, будет в большинстве ваших вариантов использования)
- Если мы отправляем синхронизацию, то тупик. В этой очереди больше ничего не будет выполняться. Это худшее, что могло случиться.
- В случае отправки async код будет выполнен в конце всего кода, уже отправленного в эту очередь (включая, помимо прочего, код, выполняющийся прямо сейчас в someMethod)
Поэтому будьте особенно осторожны при использовании метода синхронизации и убедитесь, что вы не находитесь в той же очереди, в которую отправляете.
Надеюсь, это поможет вам лучше понять.
person
Enricoza
schedule
18.11.2019
DQ.main.async
, тогда задача будет асинхронно работать в какой-то другой фоновой очереди, и по достижении завершения вернет управление в основном потоке. Почему вы считаете, что вызов async в основной очереди приведет к тому, что этот фрагмент кода будет выполнен в некоторой другой очереди, чем основная очередь? В какой бы очереди вы ни вызывали async / sync, код будет выполнен. Единственная разница в том, будет ли ваша текущая очередь ждать результата или нет. - person Roope   schedule 18.11.2019