Avec Swift 5.1, Grand Central Dispatch offre de nombreuses façons de résoudre votre problème. Selon vos besoins, vous pouvez choisir l'un des sept modèles illustrés dans les extraits Playground suivants.
Le guide de programmation Apple Developer Concurrency indique à propos deDispatchGroup
:
Les groupes de répartition sont un moyen de bloquer un thread jusqu'à ce qu'une ou plusieurs tâches aient fini de s'exécuter. Vous pouvez utiliser ce comportement dans les endroits où vous ne pouvez pas progresser jusqu'à ce que toutes les tâches spécifiées soient terminées. Par exemple, après avoir distribué plusieurs tâches pour calculer certaines données, vous pouvez utiliser un groupe pour attendre ces tâches, puis traiter les résultats lorsqu'ils sont terminés.
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. Utilisation de DispatchGroup
, DispatchGroup
's wait()
, DispatchGroup
' s enter()
et 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
*/
Notez que vous pouvez également mélanger DispatchGroup
wait()
avec DispatchQueue
async(group:qos:flags:execute:)
ou mélanger DispatchGroup
enter()
et DispatchGroup
leave()
avec DispatchGroup
notify(qos:flags:queue:execute:)
.
Grand Central Dispatch Tutorial for Swift 4: L' article de la partie 1/2 de Raywenderlich.com donne une définition des barrières :
Les barrières de répartition sont un groupe de fonctions agissant comme un goulot d'étranglement de style série lors de l'utilisation de files d'attente simultanées. Lorsque vous soumettez un DispatchWorkItem
à une file d'attente de distribution, vous pouvez définir des indicateurs pour indiquer qu'il doit être le seul élément exécuté sur la file d'attente spécifiée pour cette heure particulière. Cela signifie que tous les articles soumis à la file d'attente avant la barrière d'expédition doivent être terminés avant leDispatchWorkItem
exécution testament.
Usage:
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 a écrit les lignes suivantes dans le billet de blog The GCD Handbook :
En utilisant un sémaphore, nous pouvons bloquer un thread pendant une durée arbitraire, jusqu'à ce qu'un signal d'un autre thread soit envoyé. Les sémaphores, comme le reste de GCD, sont thread-safe et peuvent être déclenchés de n'importe où. Les sémaphores peuvent être utilisés lorsqu'il existe une API asynchrone que vous devez rendre synchrone, mais que vous ne pouvez pas la modifier.
La référence de l'API Apple Developer donne également la discussion suivante pour l' DispatchSemaphore
init(value:)
initialiseur:
La transmission de zéro pour la valeur est utile lorsque deux threads doivent réconcilier l'achèvement d'un événement particulier. Passer une valeur supérieure à zéro est utile pour gérer un pool fini de ressources, où la taille du pool est égale à la valeur.
Usage:
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 référence de l'API Apple Developer indique OperationQueue
:
Les files d'attente d'opérations utilisent la libdispatch
bibliothèque (également appelée Grand Central Dispatch) pour lancer l'exécution de leurs opérations.
Usage:
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
*/