GCD和Operation/OperationQueue 看这一篇文章就够了
Grand Central Dispatch简称GCD,是苹果公司为多核的并行运算提出的解决方案, 允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行。...
Grand Central Dispatch简称GCD,是苹果公司为多核的并行运算提出的解决方案, 允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行。GCD会自动利用更多的CPU内核(比如双核、四核), 自动管理线程的生命周期(创建线程、调度任务、销毁线程)。
下面逐一介绍DispatchQueue, Operation和OperationQueue.
文中的示例代码均可参见我的GitHub: https://github.com/zhihuitang/GCDExample
1. DispatchQueue
GCD的基本概念就是DispatchQueue。DispatchQueue是一个对象,它可以接受任务,并将任务以FIFO(先到先执行)的顺序来执行。DispatchQueue可以是并发的或串行的, 它有3种队列类型:
- Main queue
- Global queue
- Custom queue
Main queue运行在系统主线程.它是一个串行队列,我们所有的UI刷新都发生在Main queue. 获取Main queue的方法很简单:
// Get the main queue
let mainQueue = DispatchQueue.main
如果要在非Main queue线程中直接刷新UI, 运行时会出exception. 一般的做法是将代码放在Main queue中异步执行:
function DisplayWindowSize(){
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
}
1.2 Global queues(并行Concurrent)
如果要在后台执行非UI相关的工作, 一般把这部分工作放在Global queue. Global queue是一种系统内共享的并行的队列. 申请Global queue的方法很简单:
// Get the .userInitiated global dispatch queue
let userQueue = DispatchQueue.global(qos: .userInitiated)
// Get the .default global dispatch queue
let defaultQueue = DispatchQueue.global()
Global queue队列有四种优先级: 高, 缺省, 低, 后台. 在实际申请Global queue时,我们不需直接指定优先级, 只需申明所需的(QoS)类型, Qos间接的决定了这些queue的优先级
例如:
DispatchQueue.global(qos: .userInteractive)The QoS classes are:
DispatchQueue.global(qos: .userInitiated)
DispatchQueue.global() // .default qos
DispatchQueue.global(qos: .utility)
DispatchQueue.global(qos: .background)
DispatchQueue.global(qos: .unspecified)
- User-interactive
- User-initiated
DispatchQueue.global(qos: .userInitiated).async {
let overlayImage = self.faceOverlayImageFromImage(self.image)
DispatchQueue.main.async {
self.fadeInNewImage(overlayImage)
}
}
- Utility
- Background
1.3 Custom queues
用户创建的Custom queues默认的是串行的, 如果指定了attributes为concurrent则为并行的. 下面我们用代码演示串行队列/并行队列的区别.
- Serial Queue
func task1() {上面代码的输出为:
print("Task 1 started")
// make task1 take longer than task2
sleep(1)
print("Task 1 finished")
}
func task2() {
print("Task 2 started")
print("Task 2 finished")
}
example(of: "Serial Queue") {
let mySerialQueue = DispatchQueue(label: "com.crafttang.serialqueue")
mySerialQueue.async {
task1()
}
mySerialQueue.async {
task2()
}
}
sleep(2)
--- Example of: Serial Queue ---
Task 1 started
[ spent: 0.00026 ] seconds
Task 1 finished
Task 2 started
Task 2 finished
从上可以看出, task1和task2是顺序运行的, 只有task1执行完了后task2才可以执行.由于task1和task2都是异步(asyc)执行的, 所以不会阻塞当前线程, 2个任务执行的时间只有0.00026秒.
- Concurrent Queue
example(of: "Concurrent Queue") {
let concurrentQueue = DispatchQueue(label: "com.crafttang.currentqueue", attributes: .concurrent)
concurrentQueue.async {
task1()
}
concurrentQueue.async {
task2()
}
}
sleep(2)
上面的输出为:
--- Example of: Concurrent Queue ---从上面可以看出, task1和task2是并发执行的, task1启动后, 由于执行时间需要1s, 这个时候task2也可以同步运行, 所以我们可以看到task1启动后, 立即启动task2, 然后task2完成, task1完成.
Task 1 started
Task 2 started
Task 2 finished
[ spent: 0.00034 ] seconds
Task 1 finished
task1和task2都是异步(async)运行的,所以它们花费的时间仍然很短, 只有0.00034秒.
2. DispatchGroup同步(Synchronous) vs. 异步(Asynchronous)
- 对于一个任务(function), 可以在GCD队列里同步运行, 也可以异步运行。
- 同步运行的任务, 不开启新的线程, 会阻塞当前线程, 等任务完成才返回。
- 异步运行的任务, 会开启新的线程, 不会阻塞当前线程, 分发任务后立即返回,不用等任务完成。
DispatchGroup实例用来追踪不同队列中的不同任务。当group里所有事件都完成GCD API有两种方式发送通知,第一种是DispatchGroup.wait,会阻塞当前进程,等所有任务都完成或等待超时。第二种方法是使用DispatchGroup.notify,异步执行闭包,不会阻塞当前线程。
example(of: "DispatchGroup") {
let workerQueue = DispatchQueue(label: "com.crafttang.dispatchgroup", attributes: .concurrent)
let dispatchGroup = DispatchGroup()
let numberArray: [(Any,Any)] = [("A", "B"), (2,3), ("C", "D"), (6,7), (8,9)]
for inValue in numberArray {
workerQueue.async(group: dispatchGroup) {
let result = slowJoint(inValue)
print("Result = (result)")
}
}
//dispatchGroup.wait(timeout: .now() + 1)
let notifyQueue = DispatchQueue.global()
dispatchGroup.notify(queue: notifyQueue) {
print("
关注 Cocoa开发者社区
微信扫一扫关注公众号