IOS任务管理之GCD使用

前言:

     前天学了IOS的NSOperation基本使用,咱们得知NSOperation也是基于IOS GCD(Grand Central Dispatch)实现,其实在作IOS开发中GCD已经基本上可以知足大部分需求。做为IOS开发工程师颇有必要对GCD作个全面了解,今天一边写demo一边对比总结一下GCD使用。并发

了解GCD

    GCD是Grand Central Dispatch的简称,它是基于C语言的。若是使用GCD,彻底由系统管理线程,咱们不须要编写线程代码。只需定义想要执行的任务,而后添加到适当的调度队列(dispatch queue)。GCD会负责建立线程和调度你的任务,系统直接提供线程管理。app

执行方式

    使用线程就离不开线程队列的执行方式和任务的执行方式,大体分如下几个:异步

  • 串行(Serial):让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)async

  • 并行(Concurrent):可让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效。函数

  • 同步(Synchronous):在当前线程中执行任务,不具有开启新线程的能力spa

  • 异步(Asynchronous):在新的线程中执行任务,具有开启新线程的能力线程

调度队列

    上面了解到Dispatch 经过分发开发者提供的不一样queue来调度任务,咱们来看下GCD有哪些队列。3d

队列类型 建立方式

主线程串行队列(mian)code

dispatch_get_main_queue();blog

自定义串行队列(Serial)

dispatch_queue_create("MySerialQueue", DISPATCH_QUEUE_SERIAL);

自定义并行队列(Concurrent)

dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

全局并行队列(global)

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

添加执行任务的方式大体有两种:dispatch_sync 同步执行任务函数,不会开启新的线程,dispatch_async 异步执行任务函数,会开启新的线程,接下来分别看下他们的使用示例;

主线程串行队列(mian)

    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(mainQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_async(mainQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_async(mainQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

注意:

  主线程串行队列执行在主线程中,通常使用都是调用dispatch_async添加任务,使用dispatch_sync添加任务会致使死锁问题。

运行结果:

经过运行结果能够得知,虽然任务是经过dispatch_async添加执行的,可是并无建立子线程去执行任务,而是执行在主线程中。

自定义串行队列(Serial)

  有时咱们须要建立一个串行任务而且须要执行在子线程中,这时就须要建立串行队列,进行异步添加调用方式执行任务。

 
    dispatch_queue_t mySerialQueue = dispatch_queue_create("MySerialQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(mySerialQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    
    dispatch_async(mySerialQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    
    dispatch_async(mySerialQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

运行结果:

 

 能够看出串行队列异步执行建立了一个线程,而且是依次执行。

全局并行队列(global)

  相对与串行任务队列,有时咱们须要同时执行多个任务,这个时候咱们就须要使用并行任务队列了,这里咱们采用所有并行队列。

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_async(globalQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_async(globalQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

这里能够根据不一样的优先级建立不一样的所有任务队列

  • DISPATCH_QUEUE_PRIORITY_HIGH //高优先级
  • DISPATCH_QUEUE_PRIORITY_DEFAULT //默认优先级
  • DISPATCH_QUEUE_PRIORITY_LOW  //低优先级
  • DISPATCH_QUEUE_PRIORITY_BACKGROUND //后台执行

运行结果:

三个任务几乎是同时进行的,并且动态为每一个任务开辟了一个线程用于执行任务。并行队列尽可能使用异步添加任务的方式调用,同步添加任务方式调用不会建立子线程而是任务所有同时执行在主线程中致使UI卡死。

自定义并行队列(Concurrent)

    dispatch_queue_t myConcurrentQueue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(myConcurrentQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_async(myConcurrentQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_async(myConcurrentQueue, ^{
        //在block里写要执行的任务(代码)
        NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

运行结果和所有并行队列相似。

调度队列组

   有时不管咱们串行执行多任务仍是并行执行多任务,须要这个任务组所有执行完毕以后通知咱们,这里就须要用到队列组了。

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t myConcurrentQueue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

    //dispatch_group_async用于把不一样的任务归为一组
    //dispatch_group_notify当指定组的任务执行完毕以后,执行给定的任务

    dispatch_group_async(group, myConcurrentQueue, ^{
        NSLog(@"currentThread-1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    dispatch_group_async(group, myConcurrentQueue, ^{
        NSLog(@"currentThread-2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    dispatch_group_async(group, myConcurrentQueue, ^{
        NSLog(@"currentThread-3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

    dispatch_group_notify(group, myConcurrentQueue, ^{
        NSLog(@"currentThread-g:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

运行结果:

 

 GCD数据同步问题

   既然是多任务执行,就难以免会出现多任务同时访问同一数据的问题,就会遇到同步的问题,串行队列不太会碰见数据同步的问题,可是并行队列必定会有数据同步的问题,IOS GCD考虑的很全面经过调用dispatch_barrier_async函数添加任务来隔离其余的任务,起到一个栅栏的做用,它等待全部位于barrier函数以前的操做执行完毕后执行,而且在barrier函数执行以后,barrier函数以后的操做才会获得执行,该函数须要同dispatch_queue_create函数生成的concurrent Dispatch Queue队列一块儿使用。

    dispatch_queue_t conCurrentQueue = dispatch_queue_create("myConCurrentQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(conCurrentQueue, ^{
        NSLog(@"currentThread-1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    dispatch_async(conCurrentQueue, ^{
        NSLog(@"currentThread-2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    dispatch_barrier_async(conCurrentQueue, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"currentThread-b:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
        [NSThread sleepForTimeInterval:1.0];
    });
    dispatch_async(conCurrentQueue, ^{
        NSLog(@"currentThread-3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });
    dispatch_async(conCurrentQueue, ^{
        NSLog(@"currentThread-4:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

运行结果:

GCD其余经常使用函数

 dispatch_once保证在app运行期间,block中的代码只执行一次

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"只执行一次");
    //这个block里的代码,在程序执行过程当中只会执行一次。
    //好比在这里些单例的初始化
    // static YourClass *instance = nil;
    // instance = [[YourClass alloc] init];
});

dispatch_after延时添加到队列

    double delayInSeconds = 3.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        //dispatch_after函数是延迟执行某个任务,任务既能够在mainQueue中进行也能够在其余queue中进行.既能够在serial队列里执行也能够在concurrent队列里执行。
        NSLog(@"currentThread:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    });

dispatch_apply把一项任务提交到队列中屡次执行,具体是并行执行仍是串行执行由队列自己决定

NSArray *array = [NSArray arrayWithObjects:@"who",@"is",@"lcj", nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index) {
    NSLog(@"%@ : currentThread:%@ isMainThread:%@",[array objectAtIndex:index],[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});

总结:

     用了GCD以后更见佩服Apple公司了,封装的sdk 真是太完善了。简单的总结了如何使用GCD,但愿在之后的使用中有个大体了解。

相关文章
相关标签/搜索