zoukankan      html  css  js  c++  java
  • iOS多线程GCD的简单使用

    在iOS开发中,苹果提供了三种多线程技术,分别是:

    (1)NSThread

    (2)NSOperation

    (3)GCD

    简单介绍一下GCD的使用。

    GCD全称 Grand Central Dispatch,可以称之为大中央调度。实际上GCD是管理着一个线程池,如何创建线程,如何回收线程,以及分配多少个线程,这些都是GCD来控制的。在开发中,程序员是不用操作线程的相关事情,程序员只需要把应该做的操作放到相应的队列里面即可。

    一:自定义队列

    GCD中有多种队列,其中自定义的队列有两种:串行队列和并行队列

    1:串行队列:队列中的任务只会顺序执行,且一次只能够执行一个任务。也就是说,执行完一个任务后,才会执行下一个任务

    2:并行队列:可以一次执行多个任务。比如说并行队列中有10个任务,可以一次执行3个任务,这三个任务哪个先执行完了,再接着执行剩下的任务。

    注意:无论是串行队列还是并行队列,他们都是FIFO(先进先出)的。也就是说,无论是哪种队列,任务进队列的时间越早,其执行的时间就越早(只不过某些情况下任务执行的结束时间是不确定的)。

    GCD中有两种操作,分别是同步操作和异步操作

    1:同步操作:不会新开线程

    2:异步操作:会开启新的线程

    两种操作和两种队列,组合为4种情况,实际上,在开发中,有些组合基本上是不会用到的。下面用程序描述一下四种组合。

    组合一:串行队列+同步操作(不会新建线程,而且任务是一个一个的执行,因此实际上就是顺序执行),代码如下:

    - (void)gcdDemo1
    {
        //串行队列+同步操作
        dispatch_queue_t queue = dispatch_queue_create("gcddemo", DISPATCH_QUEUE_SERIAL);
        for(int i = 0; i < 10; ++i){
            dispatch_sync(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }
    

    执行结果:

    number = 1,说明是主线程,没有新开线程。

    组合二:串行队列+异步操作(因为任务要一个一个的执行,但是因为是异步操作,所以会开启一个新的线程,所有的任务都在新的线程上执行),代码如下:

    - (void)gcdDemo1
    {
        dispatch_queue_t queue = dispatch_queue_create("gcddemo", DISPATCH_QUEUE_SERIAL);
        //串行队列+异步操作
        for (int i = 0; i < 10; ++i){
            dispatch_async(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    执行结果:

    number = 2,说明开启了一个新的子线程,但仍然是顺序执行。

    组合三:并行队列+同步操作(因为同步操作不会开启新的线程,因此,即使并行队列可以一次开始多个任务,但实际上仍旧是每个任务都在主线程上执行,且按顺序执行)。代码如下:

    - (void)gcdDemo2
    {
        dispatch_queue_t queue = dispatch_queue_create("gcddemo", DISPATCH_QUEUE_CONCURRENT);
        //并行队列+同步任务
        for(int i = 0; i < 10; ++i){
            dispatch_sync(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    执行结果:

    没有开启新的线程,且按顺序执行。

    组合四:并行队列+异步操作(并行队列会一次开始多个任务,且异步操作可以开启新的线程,因此同一时刻可能会同时执行多个任务,开启多个线程,且每个任务的结束时间是不确定的)。代码如下:

    - (void)gcdDemo2
    {
        dispatch_queue_t queue = dispatch_queue_create("gcddemo", DISPATCH_QUEUE_CONCURRENT);
        //并行队列+异步任务
        for(int i = 0; i < 10; ++i){
            dispatch_async(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    执行结果:

    可以看到,开启了多个线程,且任务不是按顺序执行完的。

    二:全局队列

    为了方便开发,苹果还提供了有全局队列,全局队列实际上是并行队列,因此,全局队列的执行结果和并行队列的执行结果是一致的。代码如下:

    全局队列+同步任务:

    - (void)gcdDemo3
    {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //全局队列+同步任务
        for (int i = 0; i < 10; ++i){
            //同步任务
            dispatch_sync(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    执行结果:

    全局队列+异步任务:

    - (void)gcdDemo3
    {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //全局队列+异步任务
        for(int i = 0; i < 10; ++i){
            dispatch_async(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    执行结果:

    三:主队列

    苹果还提供了一种队列是主队列,主队列是串行队列,但是和串行队列又有差异。主队列上的任务都应该在主线程上顺序执行,没有异步的概念。也就是说,即使是异步任务在主队列上执行,也不会开启新的线程。

    主队列+异步任务:

    - (void)gcdDemo4
    {
        dispatch_queue_t queue = dispatch_get_main_queue();
        //主队列+异步任务
        for(int i = 0; i < 10; ++i){
            dispatch_async(queue,^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    执行结果:

    可以看到,没有开启新的线程,且是顺序执行。

    主队列+同步任务(会阻塞线程),代码如下:

    - (void)gcdDemo4
    {
        dispatch_queue_t queue = dispatch_get_main_queue();
        //主队列+同步任务,会阻塞
        for(int i = 0; i < 10; ++i){
            dispatch_sync(queue, ^{
                NSLog(@"%@ %d",[NSThread currentThread],i);
            });
        }
    }

    阻塞原因:

    主队列中本身是有一个任务A的(主任务),且该任务A还没有执行完。在执行任务A的过程中,又插入了新的同步任务B。我们知道,串行队列中,必须先执行完一个任务后,才能继续执行另一个任务。此时的情况时:

    若想继续执行任务A,需要先把任务B执行完,若想继续执行任务B,需要先把任务A执行完,因此造成了阻塞。

    在开发中,应该避免这种阻塞的情况。

  • 相关阅读:
    flume sink两种类型 file_rool 自定义sing com.mycomm.MySink even if there is only one event, the event has to be sent in an array
    为什么引入进程20年后,又引入线程?
    As of Flume 1.4.0, Avro is the default RPC protocol.
    Google Protocol Buffer 的使用和原理
    Log4j 2
    统一日志 统一订单
    网站行为跟踪 Website Activity Tracking Log Aggregation 日志聚合 In comparison to log-centric systems like Scribe or Flume
    Percolator
    友盟吴磊:移动大数据平台的架构、实践与数据增值
    Twitter的RPC框架Finagle简介
  • 原文地址:https://www.cnblogs.com/acBool/p/5137062.html
Copyright © 2011-2022 走看看