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入门

    讲在前面 GCD、NSOperation、NSThread哪个你比较中意呢?我用的GCD很顺手啊,相信很多人也和我...

  • GCD入门

    Grand Central Dispatch(GCD) 是 iOS 开发的一个多核编程的较新的解决方法。它主要用于...

  • GCD 入门

    同步,异步:同步是指:当一个 block 被添加到 queue 时,会阻塞当前运行的线程,直到 block 中的内...

  • GCD入门(二)啦

    废话不多说,直接从GCD所提供的函数说起。 dispatch_once 相信大家对单例模式可谓是司空见惯了吧,常见...

  • 多线程之GCD

    GCD介绍 1、GCD简介 2、GCD任务和队列 3、GCD 的基本使用 4、GCD 线程间的通信 5、GCD 的...

  • GCD入门基础知识

    正式学习GCD之前,先要熟悉下列的术语: 串行与并发 1、任务串行执行就是每次只有一个任务被执行2、并发即在同一时...

  • 扩展GCD(求逆元,解同余方程等等)

    首先要知道gcd函数的基本性质:gcd(a,b)=gcd(b,a)=gcd(|a|,|b|)=gcd(b,a%b)...

  • iOS - GCD

    目录 GCD简介 GCD核心概念 GCD队列的使用 GCD的常见面试题 GCD简介 Grand Central D...

  • iOS-多线程:GCD

    GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(6种不同组合区别) GCD 线程间的通信...

  • 浅析GCD

    GCD目录: 1. GCD简介 为什么要用GCD呢? GCD可用于多核的并行运算GCD会自动利用更多的CPU内核(...

网友评论

    本文标题:GCD入门

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