现在的位置: 首页 > 综合 > 正文

《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记三

2016年10月31日 ⁄ 综合 ⁄ 共 3321字 ⁄ 字号 评论关闭

核心札记三  GCD  阅读地点:北京 肯德基店  2014.4.8

1,Grand Central Dispatch,简称GCD,iOS4开始引入的新多线程编程功能,它是异步执行任务的技术之一,是把程序中记述的线程管理用的代码在系统级中实现,由于线程管理是作为系统的一部分来实现的,因此可以统一管理,也可执行任务,这样就比以前的线程更有效率,可以说它用我们难以置信的简洁方式实现了极为复杂繁琐的多线程编程,一个具有划时代的技术;

2,所谓线程,就是一个CPU执行的CPU命令列为一条无分叉路径,程序启动时,通过最先执行的线程即为主线程,用来描绘用户界面、处理触摸屏幕的事件等;

3,GCD下的API非常简洁,使用Block来操作多线程,使用极为方便简单;

4,Dispatch Queue ,官方对GCD的说明:开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中即可,可见这一个API承担了多大的任务,它是执行处理的等待队列,追加到队列中的事件按照FIFO处理,另外执行处理时存在两种Dispatch Queue,一种是等待现在执行中处理的 Serial Dispatch Queue (即连续), 另一种是不等待现在执行中处理的Concurrent Dispatch Queue(即并发),前者放入队列中执行时候是一个一个执行,后者是并发执行,就是使用多个线程同时执行多个处理,iOS
和 OS X的核心- XNU内核决定应当使用的线程数,并只生成所需的线程执行处理,当执行处理数减少时,XUN内核会结束不再需要的线程;

5,dispatch_queue_create 可以生成Dispatch Queue,这是第一种方式,连续和并发的生成代码如下:

Serial—dispatch_queue_t  myQueue = dispatch_queue_create (“com.z”, NULL); 

Concurrent—dispatch_queue_t  myQueue = dispatch_queue_create (“com.z”, DISPATCH_QUEUE_CONCURRENT); 

即使在ARC下生成的Dispatch Queue 也必须要程序员来负责内存释放,因为Dispatch Queue并没有如同block那样具有作为OC对象来处理的技术,释放代码:dispatch_release(myQueue); 当然了也就有dispatch_retain(myQueue); 即 Dispatch Queue 也像OC一样采用引用技术来管理内存;

果需要暂停一个队列,注意暂停一个队列会阻止和该队列相关的所有代码运行--

--暂停一个队列:dispatch_suspend(myQueue); 

如果需要恢复一个队列,注意恢复和暂停的操作与内存管理中的retain和release很类似,调用dispatch_suspend会增加暂停计数,而dispatch_resume则会减少,队列只有在暂停计数变成零的情况下才开始运行-

--恢复一个队列:dispatch_resume(myQueue); 

注意,dispatch_suspend (以及dispatch_resume)在主线程上不起作用;


6,除了采用上面提到的dispatch_queue_create来生成Dispatch Queue外,系统也帮我们提供了几个,即Main Dispatch Queue 和 Global Dispatch Queue , MDQ自然是在主线程中执行的,因为主线程只有一个,所以MDQ就是Serial Dispatch Queue,追加到MDQ的处理在主线程的RunLoop中执行,另一个是GDQ是所有应用程序都能够使用的Concurrent Dispatch Queue,GDQ有四个执行优先级,高优先级-High
Priority,默认优先级-Default Priority,低优先级-Low Priority和后台优先级-Background Priority(处理内容的执行可有可无时,采用后台优先级), 下面是获取两种情况的方法:

Main Dispatch Queue - dispatch_queue_t  myMDQ = dispatch_get_main_queue();

Global Dispatch Queue  - myGDQ =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH/DEFAULT/LOW/BACKGROUND,0);

采用这种生成的队列方式不需要我们再去释放内存,所以通常我们都采用第二种方式来操作GCD,可谓相当简单啊,现在大家应该非常清楚我们为什么写GCD时都采用后者了吧;

7, dispatch_set_target_queue 可以变更执行事件的优先级, dispatch_after 可以设定某个时间后追加处理到Dispatch Queue中,

8,Dispatch Group 当队列中是并行的,那么如何处理最后执行完成的事件,GCD采用了队列组的方式,就是所有的队列都加到一个组里面,当队列都执行完成后,组会通知主线程来做一些事情,代码如下:

先创建 dispatch_group_t  myGroup = dispatch_group_create(); 

然后添加各个GDQ, dispatch_group_async(myGroup,queue,^{NSLog(@“blk0”);}); dispatch_group_async(myGroup,queue,^{NSLog(@“blk1”);}); 

最后等待全部执行后调用主线程 dispatch_group_notify(myGroup,dispatch_get_main_queue(),^{NSLog(@“done”);}); 

记得释放create的组 dispatch_release(myGroup);  

注意带有create生成的GCD的API都要做释放处理;

9,dispatch_barrier_async 这个API函数可以避免数据竞争的问题,利用它能分割多个处理,只有前面的处理完成才能接着处理后面的,这在并行中常用,即前后的并行是分开的,前面的并行完成后才会执行后面的并行,代码:

dispatch_async(queue,blk0-4_for_reading);dispatch_barrier_async(queue,blk_for_writing);dispatch_async(queue,blk4-5_for_reading); 代码非常简单,可以实现高效率的数据库访问和文件访问;

10,dispatch_async 就是 “非同步” 的意思, dispatch_sync  就是“同步” 的意思,前者在追加事件到队列是异步的,就是说不需要等待前面的事件是否已经加进去,而后面的需要等待前面的事件是否执行完成,只有完成后才可以加到队列里面继续执行;

11,dispatch_once 函数是保证在应用程序执行中只执行一次指定处理的API,这里最常用的场景就是单例模式,在生成单例对象时候使用,代码:static dispatch_once_t pred; dispatch_once(&pred,^{/*初始化*/});

12,GCD的优势在于执行代码都在系统级,系统级就是iOS 和 OS X的核心XNU内核级上实现,用于实现Dispatch Queue而使用的软件组件有:libdispatch 提供技术 Dispatch Queue,Libc(pthreads) 提供技术 pthread_workqueue,XNU内核 提供 workqueue.

总结:GCD的全面而细腻的分析,使得对GCD能够更好的知道来龙去脉,同时也分析了为什么GCD逐渐被追捧,都源于对性能的高要求,在多线程开发中,使用GCD能更高效的操作内存,使得APP运行更流畅,至此三天的阅读完成,充分感受了底层代码的强大,跟着作者思路分析完三大主流技术 ARC,Blocks和GCD,可谓受益匪浅,感谢作者告诉我们苹果源代码没有告诉我们的那些秘密。

抱歉!评论已关闭.