美文网首页
iOS GCD简介(一)

iOS GCD简介(一)

作者: FieryDragon | 来源:发表于2020-08-24 18:50 被阅读0次

Grand Central Dispatch (GCD)是异步执行任务的计数之一。一般讲应用程序中计数的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可统一管理,也可执行任务,这样就比以前的线程更有效率。

队列

Dispatch Queue :执行处理的等待队列,采用 FIFO(先进先出)的原则。

队列分为两种:

  • 串行队列:队列中的任务顺序执行;
  • 并行队列:队列中的任务通常会并发执行。这里需要强调下,根据队列的先进先出原则,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。

我们可以通过系统提供的主队类、全局队列或者自定义队列获取队列使用。

主队列

Main Dispatch Queue是在主线程中执行的队列。追加在主队列的处理在在主线程的RunLoop中执行,因此要将用户界面的界面更新等一些必须在主线程中执行的处理追加到主队列使用。
获取方式:

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
全局队列

Global Dispatch Queue 是所有用用程序都能够使用的并行队列。全局队列默认有4个执行优先级:高优先级(High Priority)、默认优先级(Default Priority)、低优先级(Low Priority)、后台优先级(Background Priority)。
获取方式:

dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
自定义队列

使用 dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr方法来创建队列。该方法传入两个参数:
第一个参数要附加到队列的字符串标签,可为NULL。
第二个参数为队列属性,识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL 为串行队列,DISPATCH_QUEUE_CONCURRENT为并发队列。

//串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.test.serialQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

任务执行方式:

  • 同步

同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
只能在当前线程中执行任务,不具备开启新线程的能力。

dispatch_sync(queue, ^{
    
});
  • 异步

异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
可以在新的线程中执行任务,具备开启新线程的能力。

dispatch_async(queue, ^{
    
});
  • 同步与异步的区别

同步任务优先级高,在线程中有执行顺序,不会开启新的线程。
异步任务优先级低,在线程中执行没有顺序,看cpu闲不闲。在主队列中不会开启新的线程,其他队列会开启新的线程。

    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_sync(concurrentQueue, ^{
        NSLog(@"2");
    });
输出结果:
2
1

队列与任务执行方式组合

队列与任务执行方式组合.png
使用注意
  • 主队列

在主队列开启异步任务,不会开启新的线程而是依然在主线程中执行代码块中的代码。为什么不会阻塞线程?

主队列开启异步任务,虽然不会开启新的线程,但是他会把异步任务降低优先级,等闲着的时候,就会在主线程上执行异步任务。

在主队列开启同步任务,为什么会阻塞线程?

在主队列开启同步任务,因为主队列是串行队列,里面的线程是有顺序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行完毕的,因为他是无限循环的,除非关闭应用程序。因此在主线程开启一个同步任务,同步任务会想抢占执行的资源,而主线程任务一直在执行某些操作,不肯放手。两个的优先级都很高,最终导致死锁,阻塞线程了。

  • 并行队列里开启同步任务不会开辟新的线程,顺序执行;只有异步才会开启新的线程,任务没有固定执行顺序

  • 串行队列开启异步任务,会开辟一条新的线程,任务顺序执行

  • 串行队列开启异步任务后嵌套同步任务造成死锁

    dispatch_queue_t serialQueue = dispatch_queue_create("com.test.serialQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(serialQueue, ^{
        
        NSLog(@"异步任务%@", [NSThread currentThread]);
        
        //下面开启同步造成死锁:因为串行队列中线程是有执行顺序的,需要等上面开启的异步任务执行完毕,才会执行下面开启的同步任务。而上面的异步任务还没执行完,要到下面的大括号才算执行完毕,而下面的同步任务已经在抢占资源了,就会发生死锁。
        
        dispatch_sync(serialQueue, ^{
            
            NSLog(@"同步任务%@", [NSThread currentThread]);
        });
        
    });
  • 串行队列开启同步任务后嵌套同步任务造成死锁
    dispatch_queue_t serialQueue = dispatch_queue_create("com.test.serialQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(serialQueue, ^{
        
        NSLog(@"同步任务%@", [NSThread currentThread]);
        
        //下面开启同步造成死锁:因为串行队列中线程是有执行顺序的,需要等上面开启的同步任务执行完毕,才会执行下面开启的同步任务。而上面的同步任务还没执行完,要到下面的大括号才算执行完毕,而下面的同步任务已经在抢占资源了,就会发生死锁。
        
        dispatch_sync(serialQueue, ^{
            
            NSLog(@"同步任务%@", [NSThread currentThread]);
        });
        
    });
  • 串行队列开启同步任务后嵌套异步任务不造成死锁
    dispatch_queue_t serialQueue = dispatch_queue_create("com.test.serialQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(serialQueue, ^{
        
        NSLog(@"同步任务%@", [NSThread currentThread]);
        
        dispatch_async(serialQueue, ^{
            
            NSLog(@"异步任务%@", [NSThread currentThread]);
        });
        
    });

请注意,队列不是线程!单个队列可以为多个工作线程提供服务,反之亦然。


  • 参考资料

iOS 多线程:『GCD』详尽总结
《Objective-C高级编程-iOS与OS X多线程和内存管理》

相关文章

网友评论

      本文标题:iOS GCD简介(一)

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