Grand Central Dispatch(GCD)概要

1、什么是GCD

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

下面举个简单的例子:

dispatch_async(queue, ^{
            /*
             
             处理长时间的任务,例如数据库访问等等
             */
            
            /*
             长时间处理完成以后,主线程使用该处理结果
             */
            dispatch_async(dispatch_get_main_queue(), ^{
                /*
                 刷新界面等
                 */
            });
        });

2、GCD的API

2.1、Dispatch Queue(执行处理的等待队列)

Dispatch Queue按照追加的顺序(先进先出FIFO)执行处理。Dispatch Queue有两种,如下所示:

Serial Dispatch Queue 等待现在执行中处理结束
Concurrent Dispatch Queue 不等待现在执行中处理结束

创建Dispatch Queue方法有如下几种:

第一种:dispatch_queue_create函数生成Dispatch Queue

dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

第一个参数指定Dispatch Queue的名称,Dispatch Queue的名称推荐使用应用程序ID这种逆序全程域名。第二个参数用来指定Dispatch Queue的类型,如果为NULL,则为Serial Dispatch Queue,如果为DISPATCH_QUEUE_CONCURRENT,则为Concurrent Dispatch Queue.

另外,需要注意如果你创建的APP的deployment target是mac OS 10.8以及以后或者ios v6.0以及以后,通过dispatch_queue_create创建的dispatch_queue_t对象以及可以被ARC管理,程序员不必手动释放。在这之前的,必须由程序员负责释放,它不在ARC的管理范围之内。因此在使用结束后通过dispatch_release函数释放。

第二种:Main Dispatch Queue/Global Dispatch Queue

这种方法是获取系统提供的标准Dispatch Queue。其中Main Dispatch Queue是在主线程中执行的Dispatch Queue;Global Dispatch Queue是所有应用程序都能使用的Concurrent Dispatch Queue,它分为四个优先级:高优先级、默认优先级、低优先级和后台优先级。

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
    //最高优先级
    dispatch_queue_t highDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    //默认优先级
    dispatch_queue_t defaultDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

2.2 dispatch_async 和 dispatch_sync

dispatch_async表示非同步地将指定的block追加到指定的Dispatch Queue中,然后立即返回。dispatch_sync表示同步地将指定的block追加到Dispatch Queue中,在追加的block结束之前,dispatch_sync函数会一直等待。下面两个例子都会发生死锁:

dispatch_queue_t queue = dispatch_get_main_queue();
    //因为使用dispatch_sync,当前线程即主线程挂起,等待block执行完毕。而block也是在主线程执行,但是主线程已经挂起,所以进入死锁状态
    dispatch_sync(queue, ^{
        NSLog(@"hello?");
    });
   dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        dispatch_sync(queue, ^{
            NSLog(@"hello?");
        });
    });

2.3 Dispatch Group

在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理,在这种情况下使用Dispatch Group。下面看两端代码:

代码1:

dispatch_group_t dispatchGroup = dispatch_group_create();
    dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_1");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_2");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_3");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_4");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_5");
    });
    dispatch_group_notify(dispatchGroup, dispatchQueue, ^{
        NSLog(@"end");
    });

代码2:

dispatch_group_t dispatchGroup = dispatch_group_create();
    dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_1");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_2");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_3");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_4");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^{
        NSLog(@"gg_5");
    });
    dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER);
    NSLog(@"end");

代码1与代码2最大的区别就是是否阻塞当前线程。代码1工作机制是:当检测到所有添加到group中处理执行结束后,就把结束处理追加到Dispatch Queue中,因此代码1不会阻塞当前线程。代码2工作机制是:当所有添加到group中处理执行结束之前,当前线程处于阻塞状态,直到group中所有处理执行完成或者超时。

另外,dispatch_group_wait函数的返回值为0,就表示全部处理都执行结束了,如果不为0,则表示超时而返回了。

2.4、dispatch_barrier_sync 和 dispatch_barrier_async

共同点:

1、等待在它前面插入队列的任务先执行完

2、等待他们自己的任务执行完再执行后面的任务

不同点:

1、dispatch_barrier_sync将自己的任务插入到队列的时候,需要等待自己的任务结束之后才会继续插入被写在它后面的任务,然后执行他们。

2、dispatch_barrier_async将自己的任务插入到队列之后,不会等待自己的任务结束,它会继续把后面的任务插入到队列,然后等待自己的任务结束后才执行后面的任务。

2.4、dispatch_suspend/dispatch_resume

dispatch_suspend(queue);//挂起指定的Dispatch Queue

dispatch_resume(queue);//恢复指定的Dispatch Queue

注意:这些函数对已经执行的处理没有影响。挂起后,追加到Dispatch Queue中但尚未执行的处理在此之后停止执行。而恢复则使得这些处理能够继续执行。

2.5、dispatch_apply

dispatch_apply是指按照指定的次数将指定的block追加到指定的Dispatch Queue中,并等待全部处理执行结束。类似dispatch_sync函数和Dispatch group的关联API,例如:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, queue, ^(size_t index) {
        NSLog(@"%zu",index);
    });
    NSLog(@"done");

2.6、dispatch_after

注意:dispatch_after函数并不是在指定时间后执行处理,而只是在指定时间追加处理到Dispatch Queue。虽然在有严格时间的要求下使用时会出现问题,但在想大致延迟执行处理时,该函数是非常有效的。

原文地址:https://www.cnblogs.com/yongbufangqi1988/p/7435514.html