GCD的三种queue
- main queue: 主线程队列.她是一个串行队列,一般用于更新UI
- global queue:全局队列.她是一个并行队列
- custom queue:自定义队列.定义方式:
方式一:
//串行队列
let serail_queue = dispatch_queue_create("com.zhengwenxiang", DISPATCH_QUEUE_SERIAL)
方式二:
//并行队列
let concurrent_queue = dispatch_queue_create("com.zhengwenxiang", DISPATCH_QUEUE_CONCURRENT)
这是全局队列
let global_queue = dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
//
}
DISPATCH_QUEUE_SERIAL即串行队列,DISPATCH_QUEUE_CONCURRENT即并行队列
各种队列讨论
- 串行同步
func testSerailQueueWithSync() -> Void {
for i in 0..<10 {
dispatch_sync(self.serail_queue, {
print("index=\(i)")
print("current thread is \(NSThread.currentThread())")
})
}
print("My main Thread is:\(NSThread.currentThread())")
}
串行同步.jpeg
结论:
1.index值按顺序输出,符合串行队列特征
2.Runing on main Thread: 在最后输出,会阻塞主线程
3.所有线程地址相同都是主线程地址,说明串行同步不会创建新线程,会直接使用当前线程执行队列中的任务
- 串行异步
func testSerialQueueWithAsync() -> Void {
for i in 0..<10 {
dispatch_async(self.serail_queue, {
print("index=\(i)")
print("current thread is \(NSThread.currentThread())")
})
}
print("My main Thread is:\(NSThread.currentThread())")
}
串行异步.jpeg
总结:
1.index值按顺序输出,符合串行队列特征
2.current thread地址始终相同,但与主线程地址不同,说明是同一线程执行的
3.Runing on main Thread:随机出现,并没有在最后出现,与第二点相结合说明串行异步在主线程外只创建一个新线程,并且新线程不会阻塞主线程
- 并行同步
func testConcurrentQueueWithSync() -> Void {
for i in 0..<10 {
dispatch_sync(self.concurrent_queue, {
print("index=\(i)")
print("current thread is \(NSThread.currentThread())")
})
}
print("My main Thread is:\(NSThread.currentThread())")
}
并行同步.png
总结:
与串行同步输出结果相同,依然是只有一条主线程
- 并行异步
func testConcurrentQueueWithAsync() -> Void {
for i in 0..<10 {
dispatch_async(self.concurrent_queue, {
print("index=\(i)")
print("current thread is \(NSThread.currentThread())")
})
}
print("My main Thread is:\(NSThread.currentThread())")
}
并行异步.jpeg
总结:
1.输出结果是乱序的,且线程地址不同,说明异步函数中的输出语句是并发的,由多个线程执行
2.My main Thread is:没有在最后输出,说明主线程没有被阻塞
结论:
- 同步:无论是串行还是并行都不创建新线程,都是在当前线程上按顺序执行
- 异步:
1.串行中,会创建一条线程用于执行循环语句;并行中,每执行一次任务都会创建一个线程(显然,由于机器性能问题,开辟的线程总数量是有限制的),这就导致执行顺序总是乱序的
2.串行中循环语句按顺序执行,先进先出(只会创建一条线程来执行惹怒),主线程随机出现,不会阻塞主线程
3.并行中循环语句随机执行,主线程随机出现,不会阻塞主线程
dispatch_barrier
这个之前见过,但没懂.今天看了码农界吴彦祖的讲解才理解.在这里写出了是为了做个笔记.
barrier.png看图(图是搬过来的咯).
在一个并行队列中,有多个线程和一个dispatch_barrier,而barrier的作用就是保证barrier之前的线程(block0...block3)执行完成之后才能执行barrier之后的线程(block5/block6).
这是一段测试代码
func testDispatchBarrierWithConCurrentQueue() -> Void {
for i in 0..<10 {
dispatch_async(self.concurrent_queue, {
print("index=\(i)")
})
}
for j in 0...1000 {
dispatch_barrier_sync(concurrent_queue, {
if j == 999{
print("barrier finishesd")
print("current thread is \(NSThread.currentThread())")
}
})
}
print("My main Thread is:\(NSThread.currentThread())")
for i in 10..<20 {
dispatch_async(self.concurrent_queue, {
print("index=\(i)")
})
}
}
执行结果:
barrier_sync.jpeg从图中可以看出,barrier确实起到了他的作用.但我们可以看到,barrier也阻塞了主线程.
还好,ios给我提供了两种方法,dispatch_barrier_sync
和dispatch_barrier_async
当我用使用异步方法是就不会阻塞主线程了
这是一段测试代码
func testDispatchBarrierWithConCurrentQueue() -> Void {
for i in 0..<10 {
dispatch_async(self.concurrent_queue, {
print("index=\(i)")
})
}
for j in 0...1000 {
dispatch_barrier_async(concurrent_queue, {
if j == 999{
print("barrier finishesd")
print("current thread is \(NSThread.currentThread())")
}
})
}
print("My main Thread is:\(NSThread.currentThread())")
for i in 10..<20 {
dispatch_async(self.concurrent_queue, {
print("index=\(i)")
})
}
}
执行结果:
barrier_async.jpegdispatch_barrier_async
会开辟一条新线程
同时,barrier一般只与并行队列一起使用,因为串行队列本身就是按顺序执行,没有使用barrier的必要
operation queue
-
operation queue
是基于 GCD 的面向对象的封装 -
operation queue
也是一个队列,在 iOS中用NSOperationQueue
表现 -
NSOperationQueue
:队列,添加到其中的任务都会并行执行;不遵循先进先出原则.不是一个 closure, 而是一个NSOperation
类(抽象类,不能直接生成一个对象),所以 iOS 基于NSOperation
实现了两个具象类
1.NSBlockOperation
2.NSInvicationOperation: iOS8.1后废除
使用方法一
直接通过 addOperationWithBlock
方法添加一个闭包
let queue = NSOperationQueue() // operation 队列
queue.addOperationWithBlock {
let img1 = Downloader.downloadImageWithUrl(self.imageUrls[0])
NSOperationQueue.mainQueue().addOperationWithBlock({
self.imageView01.image = img1
self.imageView01.clipsToBounds = true
})
}
使用方法二
通过 NSBlockOperation
新家一个任务,再addOperation
添加任务到队列
let op2 = NSBlockOperation {
let img2 = Downloader.downloadImageWithUrl(self.imageUrls[1])
NSOperationQueue.mainQueue().addOperationWithBlock({
self.imageView02.image = img2
self.imageView02.clipsToBounds = true
})
}
queue.addOperation(op2)
任务完成
通过第二种方式新建任务,我们任务完成后允许做一些其他操作
op2.completionBlock = {print("image2 downloaded!")}
这一步需要在将任务加入队列(即queue.addOperation(op2)
)前
For Instance
op2.completionBlock = {print("image2 downloaded!")}
queue.addOperation(op2) // 加入队列
任务控制
我们可以对任务之间新建关系,以控制他们之间的完成顺序
op3.addDependency(op4) // 关联---op3始终在op4后完成
这一步需要在将任务加入队列前
For Instance
// 任务控制
op3.addDependency(op4) // 关联---op3始终在op4后
op2.addDependency(op3)
// 添加关系后重新添加任务..记得注释掉上面的添加操作
queue.addOperation(op4)
queue.addOperation(op3)
queue.addOperation(op2)
####### 取消任务
对于任务我们可以进行取消操作.操作后,对于已完成的任务并不会做任何改变,对于未完成的任务将做取消处理.
同事,对于已建立关联的任务.前面的任务取消了,其后的任务也自然不会执行
例如,上面代码,op3取消成功了, op2就不会再执行了
取消任务代码
self.queue.cancelAllOperations()
网友评论