GCD入门

作者: 我只是个仙 | 来源:发表于2018-07-16 11:56 被阅读0次

    讲在前面

    GCD、NSOperation、NSThread哪个你比较中意呢?我用的GCD很顺手啊,相信很多人也和我一样,会对GCD熟悉的不能再熟悉,原理巴拉多网上也是一堆一堆的,这里咱们就讲讲实战好了。

    GCD分类

    按照类型分为: 串行(serial queue)和并行(concurrent queue)
    按照系统提供api分为: 主线程(main queue)、全局线程(global queue)和自定义线程(custom queue)
    • 其中main queue通过dispatch_get_main_queue()获取,是主线程,属于serial queue;
    • global queue通过dispatch_get_global_queue()获取,是全局队列,属于concurrent queue;
    • custom queue 通过dispatch_queue_create()方法定义

    需要注意的几点:

    • serial queue是串行队列,串行队列的特点是FIFO(first in first out),队列中的第一个任务完成了,才能执行第二个任务,第二个任务执行完成后开始执行第三个任务,以此类推。所以理论上需要数据安全的操作可以放到这个队列中完成,例如数据库的写操作、需要锁机制的操作,也可以达到目的。当然,如果你在serial queue里面添加的sync任务,就要明白,他可能是会阻塞线程的。

    • concurrent queue是并行队列,他的特点是第一个任务开始执行后,马上可以开始第二个任务,第三个etc. 但是先执行不代表先出栈(任务执行完毕),后执行也不代表后出栈。通常,关于数据的读操作、多图片上传等只考虑并发,不考虑顺序的操作都是可以放到这个队列中的。

    GCD相关API

    dispatch_serial_queue

    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(serialQueue, ^{
        NSLog(@"1");
    });
     dispatch_async(serialQueue, ^{
        NSLog(@"2");
    });
     dispatch_async(serialQueue, ^{
        NSLog(@"3");
    });
     dispatch_async(serialQueue, ^{
        NSLog(@"4");
    });
     dispatch_async(dispatch_get_main_queue(), ^{
        self.title = @"hello";
    });
    

    输出结果:

    2018-07-15 19:55:36.940535+0800 GCDDemo[12328:651362] 1
    2018-07-15 19:55:36.940688+0800 GCDDemo[12328:651362] 2
    2018-07-15 19:55:36.940781+0800 GCDDemo[12328:651362] 3
    2018-07-15 19:55:36.940889+0800 GCDDemo[12328:651362] 4
    

    dispatch_concurrent_queue

    dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
    });
    dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
        NSLog(@"2");
    });
    dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
        NSLog(@"3");
    });
    dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
        NSLog(@"4");
    });
    dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
        NSLog(@"5");
    });
    dispatch_group_notify(self.groupQueue, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"group queue end.");
    });
    

    输出结果:

    2018-07-15 20:00:21.782358+0800 GCDDemo[12418:657731] 2
    2018-07-15 20:00:21.782368+0800 GCDDemo[12418:657728] 3
    2018-07-15 20:00:21.782378+0800 GCDDemo[12418:657732] 4
    2018-07-15 20:00:21.782358+0800 GCDDemo[12418:657729] 1
    2018-07-15 20:00:21.782505+0800 GCDDemo[12418:657731] 5
    2018-07-15 20:00:21.782612+0800 GCDDemo[12418:657731] group queue end.
    

    dispatch_barrier_async GCD的栅栏方法
    栅栏前加入队列的任务全部执行完之后,才会执行栅栏任务,栅栏任务执行完后再执行栅栏后加入队列的任务。

    dispatch_queue_t queue = dispatch_queue_create("queue.barrier.tmp", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:2];
            NSLog(@"%d   %@",i,[NSThread currentThread]);
        });
        if(i == 5) {
            dispatch_barrier_async(queue, ^{
                NSLog(@"barrier %d   %@",i,[NSThread currentThread]);
            });
        }
    }
    

    输出结果:

    2018-07-16 10:51:54.247399+0800 GCDDemo[63628:24167474] 2   <NSThread: 0x60c00026ff40>{number = 3, name = (null)}
    2018-07-16 10:51:54.247406+0800 GCDDemo[63628:24167475] 3   <NSThread: 0x60400007fb80>{number = 4, name = (null)}
    2018-07-16 10:51:54.247410+0800 GCDDemo[63628:24167472] 4   <NSThread: 0x600000461340>{number = 7, name = (null)}
    2018-07-16 10:51:54.247414+0800 GCDDemo[63628:24167473] 1   <NSThread: 0x6080002607c0>{number = 6, name = (null)}
    2018-07-16 10:51:54.247410+0800 GCDDemo[63628:24167471] 0   <NSThread: 0x60000027ed40>{number = 5, name = (null)}
    2018-07-16 10:51:54.247411+0800 GCDDemo[63628:24167499] 5   <NSThread: 0x60c0002700c0>{number = 8, name = (null)}
    2018-07-16 10:51:54.247900+0800 GCDDemo[63628:24167499] barrier 5   <NSThread: 0x60c0002700c0>{number = 8, name = (null)}
    2018-07-16 10:51:56.250672+0800 GCDDemo[63628:24167473] 9   <NSThread: 0x6080002607c0>{number = 6, name = (null)}
    2018-07-16 10:51:56.250669+0800 GCDDemo[63628:24167499] 6   <NSThread: 0x60c0002700c0>{number = 8, name = (null)}
    2018-07-16 10:51:56.250669+0800 GCDDemo[63628:24167474] 7   <NSThread: 0x60c00026ff40>{number = 3, name = (null)}
    2018-07-16 10:51:56.250679+0800 GCDDemo[63628:24167471] 8   <NSThread: 0x60000027ed40>{number = 5, name = (null)}
    
    • 这里有必要来分析一下,barrier前面开启了六个新线程,从3开始,因为1和2 分别分配给了主线程和全区队列。当线程栅栏前面的任务全部执行完毕之后,线程空出来了,最后一个线程是8,紧接着去执行栅栏任务,栅栏任务执行完毕之后,线程抖空出来了,再从中找四个空线程去完成接下来的四个异步队列任务。

    dispatch_group_t

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"group start");
    dispatch_group_async(group, queue, ^{
        dispatch_group_enter(group); // @1
        NSLog(@"group one start");
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"group one finish");
            dispatch_group_leave(group);//@2
        });
    });
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"group finished");
    });
    
    • 1(dispatch_group_enter)和2(dispatch_group_leave)两个方法是配对出现的,机制类似于GCD的信号量,enter的时候任务书+1,leave的时候任务数-1,当任务数为0 的时候会调用dispatch_group_notify的block内容执行

      dispatch_group_async  就相当于
      dispatch_group_enter(group); 
        dispatch_async(queue, ^{
            dispatch_group_leave(group);
        });
      

    dispatch_after 延时调用

    NSLog(@"%@",[NSDate date]);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",[NSDate date]);
        NSLog(@"hello world");
    });
    

    输出结果:

    2018-07-16 11:53:52.032397+0800 GCDDemo[64332:24322897] Mon Jul 16 11:53:52 2018
    2018-07-16 11:53:54.229555+0800 GCDDemo[64332:24322897] Mon Jul 16 11:53:54 2018
    2018-07-16 11:53:54.229737+0800 GCDDemo[64332:24322897] hello world
    

    别着急还有很多~

    相关文章

      网友评论

        本文标题:GCD入门

        本文链接:https://www.haomeiwen.com/subject/liuppftx.html