Con Swift 5.1, Grand Central Dispatch ofrece muchas formas de resolver su problema. Según sus necesidades, puede elegir uno de los siete patrones que se muestran en los siguientes fragmentos de Playground.
La Guía de programación de concurrencia para desarrolladores de Apple establece lo siguienteDispatchGroup
:
Los grupos de despacho son una forma de bloquear un hilo hasta que una o más tareas terminen de ejecutarse. Puede utilizar este comportamiento en lugares donde no puede avanzar hasta que se completen todas las tareas especificadas. Por ejemplo, después de enviar varias tareas para calcular algunos datos, puede usar un grupo para esperar esas tareas y luego procesar los resultados cuando estén listas.
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
*/
# 2 El uso de DispatchGroup
, DispatchGroup
's wait()
, DispatchGroup
' s enter()
, y DispatchGroup
'sleave()
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
*/
Tenga en cuenta que también puede mezclar DispatchGroup
wait()
con DispatchQueue
async(group:qos:flags:execute:)
o mezclar DispatchGroup
enter()
y DispatchGroup
leave()
con DispatchGroup
notify(qos:flags:queue:execute:)
.
El tutorial Grand Central Dispatch para Swift 4: Parte 1/2 del artículo de Raywenderlich.com da una definición de barreras :
Las barreras de envío son un grupo de funciones que actúan como un cuello de botella de estilo en serie cuando se trabaja con colas concurrentes. Cuando envía un mensaje DispatchWorkItem
a una cola de despacho, puede establecer marcas para indicar que debe ser el único elemento ejecutado en la cola especificada para ese momento en particular. Esto significa que todos los artículos enviados a la cola antes de la barrera de envío deben completarse antes de que DispatchWorkItem
se ejecute.
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 escribió las siguientes líneas en la publicación del blog The GCD Handbook :
Usando un semáforo, podemos bloquear un hilo por una cantidad arbitraria de tiempo, hasta que se envíe una señal de otro hilo. Los semáforos, como el resto de GCD, son seguros para subprocesos y se pueden activar desde cualquier lugar. Los semáforos se pueden usar cuando hay una API asincrónica que necesita hacer sincrónica, pero no puede modificarla.
Apple Developer API Reference también ofrece la siguiente discusión para el DispatchSemaphore
init(value:)
inicializador:
Pasar cero para el valor es útil para cuando dos hilos necesitan conciliar la finalización de un evento en particular. Pasar un valor mayor que cero es útil para administrar un grupo finito de recursos, donde el tamaño del grupo es igual al 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
*/
La Referencia de la API para desarrolladores de Apple establece sobre OperationQueue
:
Las colas de operaciones usan la libdispatch
biblioteca (también conocida como Grand Central Dispatch) para iniciar la ejecución de sus operaciones.
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
*/