iOS多线程之GCD

GCD

1、概念

1>GCD是Grand Central Dispatch可以为“牛逼的中枢调度器”,是纯C语言的,提供了大量的功能强大的函数。GCD是苹果公司为多核的并行运算提出的解决方案,能够自动利用更多的CPU内核,而且GCD不需要程序员编写任何管理代码,只需告诉GCD系统想要执行什么任务。

2>基本说明

GCD是 C 语言的框架,所有GCD的函数,都是以dispatch开头的

dispatch_queue_t    queue   队列

dispatch_sync       sync    同步

dispatch_async      async   异步

3>内存管理

GCD是C语言的框架,通常碰到create,copy,retain,需要对应的release的函数,ARC的GCD除外

如果在MRC开发,必须使用dispatch_release(q);释放响应的GCD对象,否则会内存泄漏!

2、GCD当中的任务和队列

1>任务:执行什么操作

a.同步任务:顺序执行,不会开启线程,允许阻塞,不允许挂起

同步任务的作用就是在多线程开发中,让后面的所有任务等待某一个任务执行完成之后,再并发执行,例如用户登录!

b.异步任务:要在别的线程并发执行,会开启线程,不允许阻塞,允许挂起


2>队列:用来存放任务的缓存区,并专门负责调度任务,安排不同的任务去不同的线程工作。队列决定能够开启线程的数量串行最多一条,并发最多线程数量由GCD决定,队列也可以不开启线程 

a.串行队列:所有的任务都是顺序执行的,最多能开一条线程,也可以不开启,只是有开启一条线程的能力

I>串行队列定义

dispatch_queue_t q = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERVERAL);

II>系统串行队列(主队列本质上是系统定义队列其实就是一个串行队列,不需要手动创建,直接get其名字即可)

主队列:专门用来做线程见通讯的(像我们让后台完成任务,然后通知主线程更新UI)

dispatch_queue_t q = dispatch_get_main_queue();

b.并发队列:能够开启多条线程,也可以不开启,只是有开启多条线程的能力

I>并发队列定义(Concurrent)

dispatch_queue_t q = dispatch_queue_create("itcast", DISPATCH_QUEUE_CONCURRENT);

II>系统并发队列(全局队列就是一个并发队列)

全局队列:

i>系统全局的调度队列,可以方便程序员使用

ii>创建并发队列,有一个好处,在大型的商业应用中,通常需要跟踪具体的任务是由哪个队列调度的。如果程序闪退,会生成日志,发送给开发者,便于开发者解决bug!如果能够记录住崩溃所在的队列名称,可以方便排错! 

iii>最常见的 GCD 代码

- (void)gcdDemo {

    // gcd是用来处理耗时的任务

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        // 耗时的操作

        

        // 要与主线程通讯,更新UI

        dispatch_async(dispatch_get_main_queue(), ^{

            // 更新UI

        });

    });

}


c.队列的选择

串行队列:最多开一条线程,任务顺序执行,效率低,执行慢,省电。对执行顺序要求高,对并发要求不高,执行性能要求不高 

并发队列:可以开多条线程,任务并发执行,效率高,执行快,费电。对执行效率要求高,对执行顺序要求不高,可以选择并发队列!


3、GCD常用方法

1>最常见的 GCD 代码

- (void)gcdDemo {

    // gcd是用来处理耗时的任务

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        // 耗时的操作

        

        // 要与主线程通讯,更新UI

        dispatch_async(dispatch_get_main_queue(), ^{

            // 更新UI

        });

    });

}

2>单例(dispath_once)

- (void)once {

    /**

     应用场景:有些代码,我们只希望执行一次,用的最广泛的,单例设计模式!

     

     dispatch_once是"线程安全"的,在多线程执行的手,仍然能够保证只执行一次

     

     同样使用了锁,但是性能比互斥锁高很多!是苹果推荐使用的技术,目前已经达到了被滥用的程度!

     */

    

    // static保存在静态区,程序启动就存在,随着程序一起销毁

    static dispatch_once_t onceToken;

    NSLog(@"Token %ld", onceToken);

    

    dispatch_once(&onceToken, ^{

        // 块代码只能执行一次

        NSLog(@"点我了");

    });

}

3>成组工作(dispatch_group_t)

- (void)group {

    /**

     应用场景

     

     在网络上下载小说,通常应该全部下载完成之后,一次性通知用户,体验会更好!

     

     提示用户过多,会遭来用户的反感,小程序会被干掉的风险!

     提示过多,会非常费电!

     */

    // 创建组

    dispatch_group_t group = dispatch_group_create();

    

    dispatch_queue_t q = dispatch_get_global_queue(0, 0);


//dispatch_get_global_queue(long identifier, unsigned long flags);


    

    // 派发任务

    dispatch_group_async(group, q, ^{

        NSLog(@"下载小说 A %@", [NSThread currentThread]);

    });

    dispatch_group_async(group, q, ^{

        NSLog(@"下载小说 B %@", [NSThread currentThread]);

    });

    dispatch_group_async(group, q, ^{

        NSLog(@"下载小说 C %@", [NSThread currentThread]);

    });

    

    // 接收通知,通知用户

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        NSLog(@"下载完成,敬请观看 %@", [NSThread currentThread]);

    });

}

3>延时处理

#pragma mark - 延时处理

- (void)delay {

    /**

     作用:从现在起,经过多少纳秒后,在queue上执行block

     

     参数

     

     when  从现在起,经过多少纳秒后,在queue上执行block

     queue 队列,不能为空

     block (异步)任务

     */

    /**

     参数:

     1. 现在

     2. 延迟时间(纳秒)

     */

    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));

    

    dispatch_after(when, dispatch_get_main_queue(), ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

    

    // 全局队列会延时多少时间后新建线程执行block

    dispatch_after(when, dispatch_get_global_queue(0, 0), ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

    

    // 串行队列会延时多少时间后新建线程执行block

    dispatch_after(when, dispatch_queue_create("itcast", NULL), ^{

        NSLog(@"==> %@", [NSThread currentThread]);

    });

}



4、执行任务

程序员只需要将任务放入队列,GCD会自动取出队列中的任务,放入到相应的线程中执行,而且执行过程是有CPU通过时间片轮转控制的,可以任务执行是随机的


小结

1、通常只考虑使用异步任务在并发队列的情况来解决实际问题

2、UI控件在iOS中是xian线程不安的

3、同步任务是需要等待上一个任务完成后,在执行当前任务的

4>在主队列中只能使用异步任务,同步任务会死锁

分析:主队列其实就是一个串行队列,串行队列中的任务,要求顺序执行,而且允许阻塞(不允许挂起,挂起任务会放到等待队列中去,等待下次就绪再执行)。如果恰巧队列中的任务是同步任务(同步任务要求等待上一个任务完成,才能执行下一个任务),那么,如果主队列中任务是嵌套的,比如B任务嵌套于A任务内,而且A,B都被放进主队列,这时候由于B任务嵌套于A任务内,要执行B任务就必须先让A任务执行完成,而完成A任务就必须执行B任务,只有B任务执行完才可以完成A任务。这要A,B任务就要彼此等待对方完成,形成死锁

5>或得当前队列的方法[NSThread currentThreah]

6>"一次性","分组","延时"特殊功能,都是NSOperation不具备的



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值