网络多线程iOS Developer程序员

iOS--GCD的API的理解与使用

2017-04-10  本文已影响71人  黑白灰的绿i

什么是GCD?

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

Dispatch Queue

含义是,执行处理的等待队列。
在执行处理时有两种Dispatch Queue

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

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

举例对比:

dispatch_async(queue, blk1);
dispatch_async(queue, blk2);
dispatch_async(queue, blk3);
dispatch_async(queue, blk4);
dispatch_async(queue, blk5);
dispatch_async(queue, blk6);
dispatch_async(queue, blk7);

当queue为Serial Dispatch Queue 时,因为需要等待现在执行中的处理结果,所以程序会相继执行1234567。
当queue为Concurrent Dispatch Queue时,因为不需要等待现在执行中的处理结果,所以先执行1,无论1有没有执行完都会执行2,以此类推,顺序是会改变的。此中执行方法开启的线程数量取决于当前系统的状态。

dispatch_queue_create

通过GCD的API生成Dispatch Queue。

dispatch_queue_t queue=dispatch_queue_create("com.like.same", NULL);

第一个参数指定Serial Dispatch Queue的名称,该名称会出现在应用程序崩溃时所生成的CrashLog中。可以但是不推荐为NULL。
第二个参数指定为NULL。
dispatch_queue_create函数可生成人一多个Dispatch Queue。虽然在一个Serial Dispatch Queue中同时只能执行一个追加处理,但是如果将处理分别追加到四个Serial Dispatch Queue中,各个Serial Dispatch Queue执行一个,即为同时执行四个处理。
通过dispatch_queue_creat函数生成的Dispatch Queue在使用结束后通过dispatch release函数释放。

dispatch_release(queue);
多个线程更新相同资源导致数据竞争时使用Serial Dispatch Queue。

Main Dispatch Queue/Global Dispatch Queue

获取系统标准提供的Dispatch Queue。

    //   Main Dispatch Queue的获取方法
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    //  Global Dispatch Queue高优先级获取方法
    dispatch_queue_t highQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    
    //   Global Dispatch Queue默认优先级获取方法
    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //   Global Dispatch Queue低优先级获取方法
    dispatch_queue_t lowQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    
    //   Global Dispatch Queue后台优先级的获取方法
    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

dispatch_set_target_queue

变更生成的Dispatch Queue的执行优先级要使用dispatch_set_target_queue函数。
eg:

    dispatch_queue_t myQueue = dispatch_queue_create("com.like.same", NULL);
    
    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    
    dispatch_set_target_queue(myQueue, backgroundQueue);

在必须将不可并行执行的处理追加到多个Serial Dispatch Queue中时,如果使用dispatch_set_target_queue 函数将目标指定为某一个Serial Dispatch Queue,即可防止处理并行执行。

dispatch_after

指定时间后执行处理的情况,可使用dispatch_after函数来实现。
eg:

    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
    
    dispatch_after(time, dispatch_get_main_queue(), ^{
        
        NSLog(@"666");
        
    });

第一个参数时指定时间用的dispatch_time_t类型的的值。
第二个参数是指定要追加处理的Dispatch Queue。
dispatch_time函数能够获取从第一个参数dispatch_time_t类型值中指定的时间开始,到第二个参数指定的单位时间后的时间。上面的代码中第一个参数代表现在。
dispatch_time函数通常用于计算相对时间,而dispatch_walltime函数用语计算绝对时间。
eg:

dispatch_time_t getDispatchTimeByDate(NSDate * date)
{
    NSTimeInterval interval;
    double second, subsecond;
    struct timespec time;
    dispatch_time_t milestone;
    
    interval = [date timeIntervalSince1970];
    subsecond = modf(interval, &second);
    time.tv_sec = second;
    time.tv_nsec = subsecond * NSEC_PER_SEC;
    milestone = dispatch_time(&time, 0);
    
    return milestone;
}

Dispatch Group

再追加到Dispatch Queue中的多个处理全部请求结束后想要执行结果处理,这种情况下使用Dispatch Group。
eg:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk0");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk2");
    });
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"done");
    });

打印结果为:

blk1
blk0
blk2
done

由于多个线程并行执行,所以执行的顺序会发生改变,但是done一定是在最后输出。

Dispatch Group.png

另外,在Dispatch Group中也可以使用dispatch_group_wait函数仅等待全部处理执行结束。

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

第二个参数为等待的时间这里使用的是永久,也就是当处理未结束,程序将一直等待下去,中途不能取消。
如果dispatch_group_wait函数的返回值不为0,就意味着虽然经过了指定的时间,但属于Dispatch Group的某一个处理还在执行中,如果返回0,那么全部处理执行结束。
一旦调用dispatch_group_wait函数,该函数处于调用的状态而不反回。

dispatch_barrier_async

dispatch_barrier_async函数会等待追加到Concurrent Dispatch Queue上的并行执行的处理全部结束之后,再将指定的处理追加到该Concurrent Dispatch Queue中。然后由dispatch_barrier_async函数处理完毕之后,Concurrent Dispatch Queue再回复为一般动作(继续并行执行)。
eg:

    dispatch_async(queue, blk0);
    dispatch_async(queue, blk1);
    dispatch_async(queue, blk2);
    dispatch_barrier_async(queue, blk);
    dispatch_async(queue, blk3);
    dispatch_async(queue, blk4);
    dispatch_async(queue, blk5);

执行结果恒为012在前,blk在中,345在后。

使用Concurrent Dispatch Queue和dispatch_barrier_async函数可实现高效率的数据库访问和文件访问。

图例:


dispatch_barrier_async.png

dispatch_sync

dispatch_async中的“async”意味着非同步,就是将指定的Block非同步的追加到指定Dispatch Queue中,dispatch_async函数不做任何等待。
“sync”则意味着同步,就是将指定的Block非同步的追加到指定Dispatch Queue中,在追加的block结束前,dispatch_sync函数会一直等待。
eg:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_sync(queue, ^{
        NSLog(@"上面处理已经结束");
    });

一旦调用dispatch_sync函数,那么指定的处理执行结束之前,该函数不会返回。可以说是简易版的dispatch_group_wait。
dispatch_barrier_async函数的作用是在等待追加的处理全部结束之后,再追加处理到Dispatch Queue中,此外,它还与dispatch_sync函数相同,会等待追加处理的执行结果。
但是频繁使用dispatch_sync容易造成死锁。
eg:

 //  造成死锁
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"????");
    });
    
    //   同样造成死锁
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        dispatch_sync(queue, ^{
            NSLog(@"???");
        });
    });

dispatch_once

dispatch_once函数是保证在应用程序执行中只执行一次指定处理的API。
单例模式:

static Singleton* _instance = nil;
+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
    _instance = [[super allocWithZone:NULL] init] ;
}) ;
return _instance ;
}

+(id) allocWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}

-(id) copyWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}

dispatch_apply

该函数是dispatch_sync函数和Dispatch Group的关联API。按照指定的次数将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束。
eg:

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

由于此函数与dispatch_sync函数一样会等待处理执行结束,所以最好在dispatch_async函数中非同步的执行dispatch_apply函数。

dispatch_suspend/dispatch_resume

dispatch_suspend函数挂起指定的Dispatch Queue。

dispatch_suspend(queue);

dispatch_resume函数恢复指定的dispatch Queue。

dispatch_resume(queue);

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

Dispatch Semaphore

待续。。。。

上一篇下一篇

猜你喜欢

热点阅读