Завдяки Swift 5.1, Grand Central Dispatch пропонує безліч способів вирішити вашу проблему. Відповідно до ваших потреб, ви можете обрати один із семи візерунків, показаних у наступних фрагментах дитячої площадки.
Посібник з програмування кон'юнктурних програм Apple Developer говорить проDispatchGroup
:
Групи диспетчеризації - це спосіб блокувати потік, поки не завершиться виконання однієї чи декількох задач. Ви можете використовувати цю поведінку в тих місцях, де ви не можете досягти успіху, поки всі визначені завдання не будуть виконані. Наприклад, після відправлення декількох завдань для обчислення деяких даних, ви можете використовувати групу для очікування цих завдань, а потім обробляти результати, коли вони будуть виконані.
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. Використовуючи DispatchGroup
, DispatchGroup
'S wait()
, DispatchGroup
' s enter()
і 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
*/
Зауважте, що ви також можете змішувати DispatchGroup
wait()
з DispatchQueue
async(group:qos:flags:execute:)
або змішувати DispatchGroup
enter()
і DispatchGroup
leave()
з DispatchGroup
notify(qos:flags:queue:execute:)
.
Grand Central Dispatch Tutorial for Swift 4: Стаття 1/2 статті від Raywenderlich.com дає визначення бар'єрів :
Диспетчерські перешкоди - це група функцій, що виконують роль вузького місця в серійному стилі при роботі з паралельними чергами. Під час подання DispatchWorkItem
до черги відправлення ви можете встановити прапори, які вказують, що це повинен бути єдиний елемент, виконаний у зазначеній черзі на цей конкретний час. Це означає, що всі пункти, подані до черги перед бар'єром відправки, повинні заповнитись перед виконанням DispatchWorkItem
заповіту.
Використання:
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
*/
Сорош Ханлу написав наступні рядки в публікації блогу " Довідник ГДЧ" :
Використовуючи семафор, ми можемо заблокувати потік протягом довільної кількості часу, поки не буде надісланий сигнал з іншої нитки. Семафори, як і решта GCD, безпечні для ниток, і їх можна спрацьовувати з будь-якого місця. Семафори можна використовувати, коли є асинхронний API, який потрібно зробити синхронним, але ви не можете його змінити.
Довідник API розробника Apple також дає наступне обговорення для DispatchSemaphore
init(value:)
ініціалізатора:
Подача нуля для значення корисна для тих випадків, коли потрібно два потоки узгодити завершення конкретної події. Передача значення, що перевищує нуль, корисна для управління кінцевим пулом ресурсів, де розмір пулу дорівнює значенню.
Використання:
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
*/
Довідник API розробника Apple говорить про OperationQueue
:
Черги операцій використовують libdispatch
бібліотеку (також відому як Grand Central Dispatch) для ініціювання виконання своїх операцій.
Використання:
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
*/