在Swift 5.1中,Grand Central Dispatch提供了许多解决问题的方法。根据您的需求,您可以选择以下Playground片段中展示的七种模式之一。
苹果开发者并发编程指南介绍了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")
}
#2. 使用
DispatchGroup
,
DispatchGroup
的
wait()
,
DispatchGroup
的
enter()
和
DispatchGroup
的
leave()
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")
}
请注意,您还可以混合使用
DispatchGroup
wait()
和
DispatchQueue
async(group:qos:flags:execute:)
,或者混合使用
DispatchGroup
enter()
和
DispatchGroup
leave()
与
DispatchGroup
notify(qos:flags:queue:execute:)
。
Raywenderlich.com上的Swift 4 Grand Central Dispatch教程:第1/2部分文章给出了barriers的定义:
调度屏障是一组函数,作为并发队列工作时的串行式瓶颈。当您向调度队列提交
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")
}
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)
Soroush Khanlou在The GCD Handbook博客文章中写道:
使用信号量,我们可以阻止一个线程任意地等待,直到来自另一个线程的信号被发送。像GCD的其余部分一样,信号量是线程安全的,并且它们可以从任何位置触发。当您需要将异步API变为同步API但无法修改它时,可以使用信号量。
苹果开发者API参考还为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")
}
关于OperationQueue
,苹果开发者API参考文档中这样描述:
操作队列使用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
*/