美文网首页
Swift: GCD基本知识与 Operation Queue

Swift: GCD基本知识与 Operation Queue

作者: 婉卿容若 | 来源:发表于2016-06-13 11:41 被阅读1269次

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_syncdispatch_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.jpeg

dispatch_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()

下载地址

demo地址

相关文章

网友评论

      本文标题:Swift: GCD基本知识与 Operation Queue

      本文链接:https://www.haomeiwen.com/subject/awdydttx.html