Com o Swift 5.1, o Grand Central Dispatch oferece várias maneiras de resolver seu problema. De acordo com suas necessidades, você pode escolher um dos sete padrões mostrados nos seguintes snippets do Playground.
O Guia de Programação de Concorrência para Desenvolvedor da Apple declara sobreDispatchGroup
:
Grupos de distribuição são uma maneira de bloquear um encadeamento até que uma ou mais tarefas concluam a execução. Você pode usar esse comportamento em locais onde não pode progredir até que todas as tarefas especificadas estejam concluídas. Por exemplo, após despachar várias tarefas para calcular alguns dados, você pode usar um grupo para aguardar essas tarefas e depois processar os resultados quando eles forem concluídos.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let group = DispatchGroup()
queue.async(group: group) {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
queue.async(group: group) {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
group.notify(queue: queue) {
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let group = DispatchGroup()
group.enter()
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
group.leave()
}
group.enter()
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
group.leave()
}
queue.async {
group.wait()
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
Note que você também pode misturar DispatchGroup
wait()
com DispatchQueue
async(group:qos:flags:execute:)
ou misturar DispatchGroup
enter()
eDispatchGroup
leave()
com DispatchGroup
notify(qos:flags:queue:execute:)
.
Tutorial de Despacho da Grand Central para Swift 4: Parte 1/2 artigo da de Raywenderlich.com fornece uma definição para barreiras :
Barreiras de expedição são um grupo de funções que atuam como um gargalo no estilo de série ao trabalhar com filas simultâneas. Ao enviar um DispatchWorkItem
para uma fila de despacho, você pode definir sinalizadores para indicar que esse deve ser o único item executado na fila especificada para esse horário específico. Isso significa que todos os itens enviados para a fila antes da barreira de expedição devem ser concluídos antes da DispatchWorkItem
execução.
Uso:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
queue.async(flags: .barrier) {
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
let dispatchWorkItem = DispatchWorkItem(qos: .default, flags: .barrier) {
print("#3 finished")
}
queue.async(execute: dispatchWorkItem)
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
Soroush Khanlou escreveu as seguintes linhas na postagem do blog The GCD Handbook :
Usando um semáforo, podemos bloquear um thread por um período arbitrário de tempo, até que um sinal de outro thread seja enviado. Os semáforos, como o restante do GCD, são seguros para threads e podem ser acionados de qualquer lugar. Semáforos podem ser usados quando há uma API assíncrona que você precisa tornar síncrona, mas não pode modificá-la.
O Apple Developer API Reference também fornece a seguinte discussão para DispatchSemaphore
init(value:)
inicializador:
Passar zero para o valor é útil quando dois encadeamentos precisam reconciliar a conclusão de um evento específico. Passar um valor maior que zero é útil para gerenciar um conjunto finito de recursos, em que o tamanho do conjunto é igual ao valor.
Uso:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let semaphore = DispatchSemaphore(value: 0)
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
semaphore.signal()
}
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
semaphore.signal()
}
queue.async {
semaphore.wait()
semaphore.wait()
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
A Referência da API do desenvolvedor da Apple declara sobre OperationQueue
:
As filas de operação usam o libdispatch
biblioteca (também conhecida como Grand Central Dispatch) para iniciar a execução de suas operações.
Uso:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let operationQueue = OperationQueue()
let blockOne = BlockOperation {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
let blockTwo = BlockOperation {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
let blockThree = BlockOperation {
print("#3 finished")
}
blockThree.addDependency(blockOne)
blockThree.addDependency(blockTwo)
operationQueue.addOperations([blockThree, blockTwo, blockOne], waitUntilFinished: false)
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
or
#2 started
#1 started
#2 finished
#1 finished
#3 finished
*/
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let operationQueue = OperationQueue()
let blockOne = BlockOperation {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
let blockTwo = BlockOperation {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
operationQueue.addOperations([blockTwo, blockOne], waitUntilFinished: false)
operationQueue.addBarrierBlock {
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
or
#2 started
#1 started
#2 finished
#1 finished
#3 finished
*/