想熟练的应用GCD 做多线程管理和处理问题必须要知道的概念!!
1.任务: 是你想做的一件事,需要执行的操作。比如下载一张图片、发一个qq消息、在控制台打印一句话等等!!!
2.队列: 是存放任务的地方,将一个或者多个任务放在其中!可以说是一个任务寄存器,它又他自己的属性和并发方式!!!
3.并发: 指在一个队列中有多个(两个或者两个以上)任务的时候,这个队列可以同时让几个任务同时执行!!!
4.串行: 在一个队列中的所有任务,只能一个接一个的顺序执行,一个任务结束,另个一个任务才能开始!!!
5.同步:两个任务是不是同步,唯一的判断是看他是不是在同一个线程中执行(没有开启新的线程)!!
6.异步:两个任务在不同的线程中执行(同时开启的线程至少有两个!)!!
置于什么是线程,什么是进程 ……我在 NSThread 文章中有介绍!!
GCD 使用步骤:
1.明确的定制任务,就是明确在知道自己要做的操作!!!
2.选则合适的队列,将任务放入队列中!!!
3.系统和更具队列的类型,取出任务!!(系统来做)
4.系统会开启一个或者多个子线程来执行取出来的任务!!(系统来做)
队列的类型和特性
1.并发队列(Concurrent Dispatch Queue)
特性: 可以多个任务同时执行(自发的根据任务的多少开启多个线程),并发的只用在异步(dispatch_async)函数中才能生效
/* 说明:全局并发队列的优先级 #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中) #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 */ // GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建 // 使用dispatch_get_global_queue函数获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT/*队列的优先级*/, 0/*此处无用,留与日后扩展所用*/);
2.串行队列 (Serial Dispatch Queue)
特性: 开启一个子线程,让任务一个接一个的顺序执行(一个任务执行结束,再开始执行下一个任务)
//使用dispatch_queue_create函数创建串行队列 dispatch_queue_t queue = dispatch_queue_create("QueueName"/*队列名称*/, NULL/*队列的属性一般为NULL*/);
// 主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行 // 使用dispatch_get_main_queue()获得主队列 dispatch_queue_t queue = dispatch_get_main_queue();
队列执行的效果
下面贴一些实例代码
1.用异步函数往并发队列中添加任务
//1.获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //2.添加任务到队列中,就可以执行任务 //异步函数:具备开启新线程的能力 dispatch_async(queue, ^{ NSLog(@"下载图片1----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"下载图片2----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"下载图片3----%@",[NSThread currentThread]); });
2.用异步函数往串行队列中添加任务
//创建串行队列 dispatch_queue_t queue= dispatch_queue_create("wendingding", NULL); //2.添加任务到队列中执行 dispatch_async(queue, ^{ NSLog(@"下载图片1----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"下载图片2----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"下载图片3----%@",[NSThread currentThread]); });
3.用同步函数往并发队列中添加任务
//创建并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //2.添加任务到队列中执行 dispatch_sync(queue, ^{ NSLog(@"下载图片1----%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"下载图片2----%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"下载图片3----%@",[NSThread currentThread]); });
4.用同步函数往串行队列中添加任务
//创建串行队列 dispatch_queue_t queue= dispatch_queue_create("wendingding", NULL); //2.添加任务到队列中执行 dispatch_sync(queue, ^{ NSLog(@"下载图片1----%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"下载图片2----%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"下载图片3----%@",[NSThread currentThread]); });
备注: 同步函数不具备开启线程的能力,无论是什么队列都不会开启线程;异步函数具备开启线程的能力,开启几条线程由队列决定(串行队列只会开启一条新的线程,并发队列会开启多条线程)。
CGD 一些特殊用途
// 一次性执行: static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"只执行一次,多用于单例模式创建单例对象"); }); // 延迟2秒执行: double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // code to be executed /*adj.已执行的;已生效的*/ on the main queue after delay NSLog(@"延时2秒后,在主线程中执行!!!"); });
GCD 的优缺点
1.在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。
// AppDelegate.h文件 @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask; // AppDelegate.m文件 - (void)applicationDidEnterBackground:(UIApplication *)application { [self beingBackgroundUpdateTask]; // 在这里加上你需要长久运行的代码 [self endBackgroundUpdateTask]; } - (void)beingBackgroundUpdateTask { self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [self endBackgroundUpdateTask]; }]; } - (void)endBackgroundUpdateTask { [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask]; self.backgroundUpdateTask = UIBackgroundTaskInvalid; }
2.将单一任务或者一组相关任务并发至全局队列中运算;将多个不相关的任务或者关联不紧密的任务并发至用户队列中运算;
3.比之线程,GCD是轻量和低负载的,但是将block提交至queue还是很消耗资源的——block需要被拷贝和入队,同时适当的工作线程需要被通知。使得它在很多地方比之专门创建消耗资源的线程更实用且快速。这关系到易用性:导致GCD易用的原因有一部分在于你可以不用担心太多的效率问题而仅仅使用它就行了。
4.GCD自动根据系统负载来增减线程数量,这就减少了上下文切换以及增加了计算效率。
5.GCD比之thread跟简单易用。由于GCD基于work unit而非像thread那样基于运算,所以GCD可以控制诸如等待任务结束、监视文件描述符、周期执行代码以及工作挂起等任务。基于block的血统导致它能极为简单得在不同代码作用域之间传递上下文。(也许吧,因人而异!)
文章到这已经结束啦,很多部分都在网络上的资料,希望对路过的人有所帮助!!!!