Dzięki Swift 5.1 Grand Central Dispatch oferuje wiele sposobów rozwiązania problemu. W zależności od potrzeb możesz wybrać jeden z siedmiu wzorów pokazanych w poniższych fragmentach placu zabaw.
Przewodnik programisty współbieżności dla programistów Apple mówi oDispatchGroup
:
Grupy wysyłania są sposobem blokowania wątku, dopóki jedno lub więcej zadań nie zakończy się. Możesz użyć tego zachowania w miejscach, w których nie można robić postępów, dopóki wszystkie określone zadania nie zostaną ukończone. Na przykład po wysłaniu kilku zadań do obliczenia niektórych danych możesz użyć grupy, aby poczekać na te zadania, a następnie przetworzyć wyniki po ich zakończeniu.
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. Korzystanie DispatchGroup
, DispatchGroup
's wait()
, DispatchGroup
' s enter()
i 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
*/
Pamiętaj, że możesz także miksować DispatchGroup
wait()
z DispatchQueue
async(group:qos:flags:execute:)
lub miksować z DispatchGroup
enter()
i .DispatchGroup
leave()
DispatchGroup
notify(qos:flags:queue:execute:)
Samouczek Grand Central Dispatch dla Swift 4: część 1/2 artykułu z Raywenderlich.com zawiera definicję barier :
Bariery wysyłki to grupa funkcji działających jako wąskie gardło w stylu szeregowym podczas pracy z równoległymi kolejkami. Kiedy przesyłasz a DispatchWorkItem
do kolejki wysyłkowej, możesz ustawić flagi wskazujące, że powinien to być jedyny element wykonywany w określonej kolejce dla tego określonego czasu. Oznacza to, że wszystkie elementy przesłane do kolejki przed barierą wysyłkową muszą zostać ukończone przed DispatchWorkItem
wykonaniem.
Stosowanie:
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 napisał następujące wiersze w poście na blogu The GCD Handbook :
Za pomocą semafora możemy blokować wątek na dowolny czas, dopóki nie zostanie wysłany sygnał z innego wątku. Semafory, podobnie jak reszta GCD, są bezpieczne dla wątków i można je uruchamiać z dowolnego miejsca. Semaforów można używać, gdy istnieje asynchroniczny interfejs API, który należy synchronizować, ale nie można go modyfikować.
Dokumentacja interfejsu API dla programistów Apple zawiera także następujące omówienie DispatchSemaphore
init(value:)
inicjatora:
Przekazywanie wartości zero jest przydatne, gdy dwa wątki muszą uzgodnić zakończenie określonego zdarzenia. Przekazywanie wartości większej niż zero jest przydatne do zarządzania skończoną pulą zasobów, w której wielkość puli jest równa wartości.
Stosowanie:
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
*/
Dokumentacja interfejsu API Apple Developer zawiera następujące informacje OperationQueue
:
Kolejki operacji używają libdispatch
biblioteki (znanej również jako Grand Central Dispatch) do inicjowania wykonywania swoich operacji.
Stosowanie:
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
*/