• 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。虽然在有严格时间的要求下使用时会出现问题,但在想大致延迟执行处理时,该函数是非常有效的。

  • 相关阅读:
    JS创建类的方法--简单易懂有实例
    CommonJS, AMD, CMD是什么及区别--简单易懂有实例
    JS回调函数--简单易懂有实例
    单链表应用(2)--使用快慢指针,如何判断是否有环,环在哪个节点
    单链表应用(1)--使用快慢指针,找链表中间值
    自定义线性结构-有序Map
    C++中final和override
    双向链表翻转
    检查“()”是否匹配并返回深度
    是否存在K
  • 原文地址:https://www.cnblogs.com/yongbufangqi1988/p/7435514.html
Copyright © 2020-2023  润新知