GCD介绍 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。简单的说它提供了IOS多核编程的解决方法,注意她是纯C语言,并且提供了非常多强大的函数,它是基于函数使用的,而不是我们面向对象里边说的方法。
原理 GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。一个任务可以是一个函数(function)或者是一个block。GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。GCD中的FIFO队列称为dispatchqueue,它可以保证先进来的任务先得到执行,即操作系统里边的先进先出,后进后出。
种类 通常来讲dispatchqueue分为3大类Serial(串行)、Concurrent 、Main dispatch queue 1.Serial 又称为private dispatch queues,同时只执行一个任务。Serialqueue通常用于同步访问特定的资源或数据。当你创建多个Serialqueue时,虽然它们各自是同步执行的,但Serialqueue与Serial queue之间是并发执行的。 2.Concurrent 又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。 3.Main dispatch queue 它是全局可用的serial queue,它是在应用程序主线程上执行任务的。
用法 1、dispatch_async 为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。1
2
3
4
5
6
7
8
9
10
11
12
/**
*1.获得全局的并发队列,由于是全局的因此不需要我们回收
*2.dispatch_get_main_queue()获取主线程,并且做一些UI更新操作
*3.我们还应该明白一个概念,dispatch_async把右边的参数(任务)提交给左边的参数(队列)进行执行。(queue:队列,block:任务)
**/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// 耗时的操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面
});
});
2、dispatch_group_async dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
*dispatch_get_global_queue参数说明右边的说明优先级,左边的是留在以后备用的,现在暂时还用不着,可以先用0代替
*
*
*
*
**/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"group1" );
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"group2" );
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"group3" );
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"updateUi" );
});
dispatch_release(group);
执行结果就是group1 group2 group3 updateUi依次打印出来
3.dispatch_queue_create配合dispatch_async使用 注意:自己创建的一定要回收这里记住一个准则凡是函数名中带有create\copy\new\retain等字眼,都需要在不需要使用这个数据的时候进行release。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//创建串行队列
dispatch_queue_t queue= dispatch_queue_create("zijichuangjian" , NULL);
//第一个参数为串行队列的名称,是c语言的字符串
//第二个参数为队列的属性,一般来说串行队列不需要赋值任何属性,所以通常传空值(NULL)
//2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"任务一----%@" ,[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务二----%@" ,[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务三----%@" ,[NSThread currentThread]);
});
//3.释放资源
dispatch_release(queue);
4.dispatch_barrier_async dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dispatch_queue_t queue = dispatch_queue_create("zijichuangjian" , DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"dispatch_async1" );
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:4];
NSLog(@"dispatch_async2" );
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async" );
[NSThread sleepForTimeInterval:4];
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"dispatch_async3" );
});
执行结果就是dispatch_async1 dispatch_async2 dispatch_barrier_async dispatch_async3依次打印出来
5.dispatch_apply 执行某个代码片段N次,相当于指定了执行次数的定时器1
2
3
dispatch_apply(10, globalQ, ^(size_t index) {
// 执行10次
});
6.dispatch_once_t 实现单例模式1
2
3
4
5
// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 需要一次执行的代码
});
7.dispatch_after延迟执行 1
2
3
4
5
6
//延迟时间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){
// 主线程更新UI操作
});
同步异步的几点总结 1.用异步函数往并发队列中添加任务1
2
3
4
5
6
7
8
9
10
11
12
13
//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.用同步函数往并发队列中添加任务1
2
3
4
5
6
7
8
9
10
11
12
13
//1.获得全局的并发队列
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]);
});
总结:不会开启新的线程,并发队列失去了并发的功能 3.用异步函数往串行队列中添加任务1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dispatch_queue_t queue = dispatch_queue_create("zijichuangjian" , DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"dispatch_async1" );
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:4];
NSLog(@"dispatch_async2" );
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async" );
[NSThread sleepForTimeInterval:4];
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"dispatch_async3" );
});
总结:会开启子线程,但是只开启一个线程 4.用同步函数往串行队列中添加任务1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dispatch_queue_t queue = dispatch_queue_create("zijichuangjian" , DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"dispatch_async1" );
});
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:4];
NSLog(@"dispatch_async2" );
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async" );
[NSThread sleepForTimeInterval:4];
});
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"dispatch_async3" );
});
总结:不会开启新的子线程
GCD的另一个用处是可以让程序在后台较长久的运行 在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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;
}
参考文档 1、 iOS开发多线程篇—GCD介绍 2、 iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用 3、 iOS多线程GCD