GCD
正在学习这块的东西 转载两篇好文章 原文地址http://www.cnblogs.com/carlton/archive/2013/06/23/3150611.html
概述
直观上理解,GCD偏向于系统级的API,也就是说它更接近于底层,在编写规范的前提下它相较NSOperation的性能要略优。而Cocoa的异步框架即NSOperation相关提供的API,更偏向于应用层面,它是对系统底层调用(包括GCD等)的封装,从功能层面上讲相较GCD更为丰富(NSOperation + Queue的形式具备一些GCD未直接包含的功能)
通过查阅官方文档以及国外一些Blog的阐述,基本达成的共识是:在APP中,尽可能的使用Cocoa,即high-level Api,除非在实际性能测试数据上发现不得不用更底层的api的时候,才进一步考虑使用GCD。
而目前国内的开发者,大多数倾向于直接使用GCD,我想最主要的原因是block思想接近于过程化,同时GCD书写起来能更简单随意。
这里引用两段话:
GCD is not restricted to system-level applications, but before you use it for higher-level applications, you should consider whether similar functionality provided in Cocoa (via NSOperation and block objects) would be easier to use or more appropriate for your needs. See Concurrency Programming Guide for more information.
Always use the highest-level abstraction available to you, and drop down to lower-level abstractions when measurement shows that they are needed.
GCD - 1
GCD从语言、运行时库、系统扩展等三个方面给让使用者更充分的操作多核设备,同时它基于队列的概念,因为每一个CPU core单位时间(时间片)内只能运行某个队列的某个task,并通过优先级、FIFO等策略进行task的切换运行。
GCD共提供三种队列形式:
1. main,即主线程,iOS的UI绘制、交互响应都要在此线程上执行
2. concurrent,并发线程队列,task的进出队列,都遵循FIFO策略,但队列中的task‘看起来’是并发执行的完成时间却可能是以任意的顺序结束。很容易理解,因为每个task的执行时间长短通常不一样。
3. serial,串行队列,在此队列中的task,one by one的执行,严格遵守FIFO
即,我们要执行一个block(task),前提是需要知道我们要将task放入哪个或哪类(上述其中之一)queue?
1. 获取一个GCD队列
获取GCD队列的方法主要有以下几种:
dispatch_queue_t dispatch_get_main_queue(void) - 获取主线程队列
dispatch_queue_t dispatch_get_global_queue(long priority,unsigned long flags) - 获取全局队列(该队列是一个concurrent队列)
dispatch_queue_t dispatch_queue_create(const char *label,dispatch_queue_attr_t attr) - 创建队列,根据attr指定被创建的队列的类型,可以为concurrent也可以为serial
2. 准备待执行的Block
dispatch_block_t ablock = ^(){ NSLog(@"Print in ##_queue @ ablock"); };
3. 将待执行的Task置于某个GCD队列中执行
dispatch_block_t block_main = ^(){ NSLog(@"Print in main_queue @ block_main"); }; dispatch_queue_t main_queue = dispatch_get_main_queue(); dispatch_async(main_queue, block_main); // 将block_main置于main_queue中执行,async方法将立刻返回,block_main中的代码将在这其中或随后的某一时刻执行
dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime,concurrent_queue, ^(void){
NSLog(@"This line will executed after 2s @ concurrent"); // 这里用了concurrent队列,如果为main队列,则效果等同:
//- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
});
// 创建一个serial队列 dispatch_queue_t serial_queue = dispatch_queue_create("SERIAL", DISPATCH_QUEUE_SERIAL); dispatch_async(serial_queue, ^(){ sleep(3); NSLog(@"block_1"); // 尽管为异步调用且延迟3秒,但由于在serial队列中,block_1仍然先于block_2被打印出来 }); dispatch_async(serial_queue, ^(){ NSLog(@"block_2"); }); // 队列在使用完毕之后必须进行release dispatch_release(serial_queue);
//因为在dispatch_async的时候,其实每个block都对该队列进行了retain,而起初我们对其进行了create(也相当于retain),所以最后需要进行显示的release。而对于main、concurrent队列,就不能进行release了