IOS任务管理之GCD使用
前言:
前天学了IOS的NSOperation基本使用,我们得知NSOperation也是基于IOS GCD(Grand Central Dispatch)实现,其实在做IOS开发中GCD已经基本上能够满足大部分需求。作为IOS开发工程师很有必要对GCD做个全面了解,今天一边写demo一边对比总结一下GCD使用。
了解GCD
GCD是Grand Central Dispatch的简称,它是基于C语言的。如果使用GCD,完全由系统管理线程,我们不需要编写线程代码。只需定义想要执行的任务,然后添加到适当的调度队列(dispatch queue)。GCD会负责创建线程和调度你的任务,系统直接提供线程管理。
执行方式
使用线程就离不开线程队列的执行方式和任务的执行方式,大致分以下几个:
串行(Serial):让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
并行(Concurrent):可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效。
同步(Synchronous):在当前线程中执行任务,不具备开启新线程的能力
异步(Asynchronous):在新的线程中执行任务,具备开启新线程的能力
调度队列
上面了解到Dispatch 通过分发开发者提供的不同queue来调度任务,我们来看下GCD有哪些队列。
队列类型 | 创建方式 |
主线程串行队列(mian) |
dispatch_get_main_queue(); |
自定义串行队列(Serial) |
dispatch_queue_create("MySerialQueue", DISPATCH_QUEUE_SERIAL); |
自定义并行队列(Concurrent) |
dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT); |
全局并行队列(global) |
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
添加执行任务的方式大致有两种:dispatch_sync 同步执行任务函数,不会开启新的线程,dispatch_async 异步执行任务函数,会开启新的线程,接下来分别看下他们的使用示例;
主线程串行队列(mian)
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(mainQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(mainQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
注意:
主线程串行队列执行在主线程中,一般使用都是调用dispatch_async添加任务,使用dispatch_sync添加任务会导致死锁问题。
运行结果:
通过运行结果可以得知,虽然任务是通过dispatch_async添加执行的,但是并没有创建子线程去执行任务,而是执行在主线程中。
自定义串行队列(Serial)
有时我们需要创建一个串行任务并且需要执行在子线程中,这时就需要创建串行队列,进行异步添加调用方式执行任务。
dispatch_queue_t mySerialQueue = dispatch_queue_create("MySerialQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(mySerialQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(mySerialQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(mySerialQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
运行结果:
可以看出串行队列异步执行创建了一个线程,并且是依次执行。
全局并行队列(global)
相对与串行任务队列,有时我们需要同时执行多个任务,这个时候我们就需要使用并行任务队列了,这里我们采用全部并行队列。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_async(globalQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(globalQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(globalQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
这里可以根据不同的优先级创建不同的全部任务队列
DISPATCH_QUEUE_PRIORITY_HIGH //高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT //默认优先级
DISPATCH_QUEUE_PRIORITY_LOW //低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND //后台执行
运行结果:
三个任务几乎是同时进行的,而且动态为每个任务开辟了一个线程用于执行任务。并行队列尽量使用异步添加任务的方式调用,同步添加任务方式调用不会创建子线程而是任务全部同时执行在主线程中导致UI卡死。
自定义并行队列(Concurrent)
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(myConcurrentQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_async(myConcurrentQueue, ^{
//在block里写要执行的任务(代码)
NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
运行结果和全部并行队列类似。
调度队列组
有时无论我们串行执行多任务还是并行执行多任务,需要这个任务组全部执行完毕之后通知我们,这里就需要用到队列组了。
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT); //dispatch_group_async用于把不同的任务归为一组
//dispatch_group_notify当指定组的任务执行完毕之后,执行给定的任务 dispatch_group_async(group, myConcurrentQueue, ^{
NSLog(@"currentThread-1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
dispatch_group_async(group, myConcurrentQueue, ^{
NSLog(@"currentThread-2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
dispatch_group_async(group, myConcurrentQueue, ^{
NSLog(@"currentThread-3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}); dispatch_group_notify(group, myConcurrentQueue, ^{
NSLog(@"currentThread-g:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
运行结果:
GCD数据同步问题
既然是多任务执行,就难以避免会出现多任务同时访问同一数据的问题,就会遇到同步的问题,串行队列不太会遇见数据同步的问题,但是并行队列一定会有数据同步的问题,IOS GCD考虑的很全面通过调用dispatch_barrier_async函数添加任务来隔离其他的任务,起到一个栅栏的作用,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行,该函数需要同dispatch_queue_create函数生成的concurrent Dispatch Queue队列一起使用。
dispatch_queue_t conCurrentQueue = dispatch_queue_create("myConCurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(conCurrentQueue, ^{
NSLog(@"currentThread-1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"currentThread-2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
dispatch_barrier_async(conCurrentQueue, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"currentThread-b:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
[NSThread sleepForTimeInterval:1.0];
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"currentThread-3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"currentThread-4:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
运行结果:
GCD其他常用函数
dispatch_once保证在app运行期间,block中的代码只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只执行一次");
//这个block里的代码,在程序执行过程中只会执行一次。
//比如在这里些单例的初始化
// static YourClass *instance = nil;
// instance = [[YourClass alloc] init];
});
dispatch_after延时添加到队列
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//dispatch_after函数是延迟执行某个任务,任务既可以在mainQueue中进行也可以在其他queue中进行.既可以在serial队列里执行也可以在concurrent队列里执行。
NSLog(@"currentThread:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
dispatch_apply把一项任务提交到队列中多次执行,具体是并行执行还是串行执行由队列本身决定
NSArray *array = [NSArray arrayWithObjects:@"who",@"is",@"lcj", nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_apply([array count], queue, ^(size_t index) {
NSLog(@"%@ : currentThread:%@ isMainThread:%@",[array objectAtIndex:index],[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
});
总结:
用了GCD之后更见佩服Apple公司了,封装的sdk 真是太完善了。简单的总结了如何使用GCD,希望在以后的使用中有个大致了解。
IOS任务管理之GCD使用的更多相关文章
- [iOS]深入理解GCD
看到一篇很好的文章,本来想翻译的,但发现已经有人翻译了,遂简单整理了一下,方便阅读学习 新博客[wossoneri.com] 什么是GCD GCD(Grand Central Dispatch)是li ...
- iOS 开发之 GCD 不同场景使用
header{font-size:1em;padding-top:1.5em;padding-bottom:1.5em} .markdown-body{overflow:hidden} .markdo ...
- iOS 开发之 GCD 基础
header{font-size:1em;padding-top:1.5em;padding-bottom:1.5em} .markdown-body{overflow:hidden} .markdo ...
- 玩转iOS开发:iOS中的GCD开发(三)
上一章, 我们了解到了GCD里的一些队列和任务的知识, 也实践了一下, 同时我们也对主队列的一些小情况了解了一下, 比如上一章讲到的卡线程的问题, 如果没有看的朋友可以去看看玩转iOS开发:iOS中的 ...
- iOS开发之GCD
GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制.它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务. GCD中的FIFO队列称为 ...
- ios线程和GCD
1.什么是进程? 进程是指在系统中正在运行的一个应用程序.比如同时打开QQ.Xcode,系统就会分别启动2个进程.截图 2.什么是线程? 1).一个进程要想执行任务,必须得有线程(每一个进程至少要有一 ...
- IOS并发编程GCD
iOS有三种多线程编程的技术 (一)NSThread (二)Cocoa NSOperation (三)GCD(全称:Grand Central Dispatch) 这三种编程方式从上到下,抽象度层次 ...
- IOS多线程(GCD)
简介 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次 ...
- ios开发多线程--GCD
引言 虽然GCD使用很广,而且在面试时也经常问与GCD相关的问题,但是我相信深入理解关于GCD知识的人肯定不多,大部分都是人云亦云,只是使用过GCD完成一些很简单的功能.当然,使用GCD完成一些简单的 ...
随机推荐
- Photoshop 画基本图形
作者:zccst 1,画三角形 按下“U”选择“多边形工具”(是个六边形的图标),在上方的菜单栏中的“边”后面输入“3”,然后在画布中拖动就是三角形了,画好后按下CTRL+ENTER键转化成选区,然后 ...
- S3C2440硬件IIC详解
S3C2440A RISC微处理器可以支持一个多主控IIC 总线串行接口.一条专用串行数据线(SDA)和一条专用串行时钟线(SCL)传递连接到IIC总线的总线主控和外设之间的信息.SDA和SCL线都为 ...
- VB.NET中网络编程所需组件WinHTTP的添加
VB.NET中网络编程所需组件: WinHTTP组件:项目-->添加引用-->COM选项卡-->Microsoft WinHTTP Services,version 5.1--> ...
- IOS开发中使用AFNetworking请求网络数据
1.把AFNetworking的文件拖放到项目中(注意不同的版本方法不一样,本历程基于版本2013): 2.使用#import "AFNetworking.h"命令把AFNetwo ...
- thinkphp ,进行关联模型的时候出现的问题,版本是3.2
看的后盾网络视频,里面操作的是3.1. 我用的是onethink,基于3.2. 在关联模式的操作时.主要是user role role_user 3个张表 视频中可以操作,但是本地操作出现问题. ...
- java实现——004替换空格
1.创建新的字符串 public class T004 { public static void main(String[] args){ System.out.println(replaceBlan ...
- p便签,去掉首行缩进
<p>fdsfdsfs</p> 使用P标签是,会自动的加上首行缩进,如果想去掉首行缩进,可以使用text-indent属性 <p style="text-ind ...
- 【USB-HID在STM32上的实现】-00-开始
前一段时间参照网上的例程搞了一阵STM32F103的HID程序,改了改例子实现了一个摇杆的外设控制功能.1通道开关量输入,2通道模拟量输入. 之后有空了总结一下,防止忘记.
- 一段神奇的代码-关于PHP字符变量奇怪现象的解释
首先神奇的PHP是支持字符数据类型的,有同学就写了这样一段代码: for ($c = 'a'; $c <= 'z'; $c++) { echo $c . ' '; } 然而结果却不是他想要的a到 ...
- 纯css三角形
三角形原理: 盒子c内容width为0,height为0,盒子给一定宽度的border,分别为四边的border设置不同的颜色,则可以得到不同样式的三角形举个简单的栗子:CSS代码 .box1{ wi ...