Con Swift 5.1, Grand Central Dispatch offre molti modi per risolvere il tuo problema. In base alle tue esigenze, puoi scegliere uno dei sette motivi mostrati nei seguenti frammenti del parco giochi.
La Guida alla programmazione della concorrenza per gli sviluppatori Apple affermaDispatchGroup
:
I gruppi di invio sono un modo per bloccare un thread fino al completamento dell'esecuzione di una o più attività. È possibile utilizzare questo comportamento in luoghi in cui non è possibile progredire fino al completamento di tutte le attività specificate. Ad esempio, dopo aver inviato diverse attività per calcolare alcuni dati, è possibile utilizzare un gruppo per attendere tali attività e quindi elaborare i risultati al termine.
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. Utilizzando DispatchGroup
, DispatchGroup
's wait()
, DispatchGroup
' s enter()
e 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
*/
Nota che si può anche mescolare DispatchGroup
wait()
con DispatchQueue
async(group:qos:flags:execute:)
o mescolare DispatchGroup
enter()
e DispatchGroup
leave()
con DispatchGroup
notify(qos:flags:queue:execute:)
.
Grand Central Dispatch Tutorial per Swift 4: l' articolo 1/2 di Raywenderlich.com fornisce una definizione per le barriere :
Le barriere di invio sono un gruppo di funzioni che agiscono come un collo di bottiglia in stile seriale quando si lavora con code simultanee. Quando si invia un DispatchWorkItem
a una coda di invio, è possibile impostare flag per indicare che dovrebbe essere l'unico elemento eseguito sulla coda specificata per quel particolare momento. Ciò significa che tutti gli articoli inviati alla coda prima della barriera di spedizione devono essere completati prima DispatchWorkItem
dell'esecuzione.
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 ha scritto le seguenti righe nel post del blog The GCD Handbook :
Usando un semaforo, possiamo bloccare un thread per un periodo di tempo arbitrario, fino a quando non viene inviato un segnale da un altro thread. I semafori, come il resto di GCD, sono thread-safe e possono essere attivati da qualsiasi luogo. I semafori possono essere usati quando c'è un'API asincrona che devi rendere sincrona, ma non puoi modificarla.
Riferimento API API per sviluppatori fornisce anche la seguente discussione per l' DispatchSemaphore
init(value:)
inizializzatore:
Il passaggio zero per il valore è utile quando due thread devono riconciliare il completamento di un evento specifico. Il passaggio di un valore maggiore di zero è utile per la gestione di un pool di risorse finito, in cui la dimensione del pool è uguale al valore.
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
*/
Il riferimento all'API per gli sviluppatori Apple indica OperationQueue
:
Le code delle operazioni utilizzano la libdispatch
libreria (nota anche come Grand Central Dispatch) per avviare l'esecuzione delle loro operazioni.
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
*/