GCD : 纯 C 语言的 API
GCD 核心
1.任务:执行什么操作
同步:永远只在当前线程
上 从上往下,依次执行
执行,这个就叫做同步
异步:永远不在当前的线程
上执行,它跑到别的线程上面去执行。
总结:同步方法 永远在当前线程上执行,所以没有开辟线程的能力。
异步方法,因为要在别的线程上去执行,所以它具有开辟线程的能力。
当遇到主队列
,这个奇葩的时候,它就不起作用
2.队列:用来存放任务
作用:将相同的任务
放在同一个队列中,方便管理
a.串行队列:
加入到里面的任务是一个一个有顺序的调度的。
串行队列,同步任务
特点:有顺序的执行,并且不会开辟新线程,就在当前线程执行
应用场景:FMDB,它为什么要设计成串行队列,同步任务,为了保证数据的安全
/**
* 串行队列,同步任务执行
*/
- (void)selrilSync {
// 1.创建任务
void (^task1)() = ^() {
NSLog(@"task1----%@", [NSThread currentThread]);
};
void (^task2)() = ^() {
NSLog(@"task2----%@", [NSThread currentThread]);
};
void (^task3)() = ^() {
NSLog(@"task3----%@", [NSThread currentThread]);
};
// 2.创建队列 串行队列
dispatch_queue_t serial =
dispatch_queue_create("cn.jingcheng", DISPATCH_QUEUE_SERIAL);
//将任务添加带队列中
dispatch_sync(serial, task1);
dispatch_sync(serial, task2);
dispatch_sync(serial, task3);
}
串行队列,异步任务
特点:有顺序的执行,并且在开辟的新的线程中执行,并且只开一条线程!!!
应用场景:耗时操作,并且有严格先后顺序
去付费网站上,下载片
登录--->付费--->下载
/**
* 串行队列,异步执行
*/
- (void)serialAsync {
void (^task1)() = ^() {
NSLog(@"task1----%@", [NSThread currentThread]);
};
void (^task2)() = ^() {
NSLog(@"task2----%@", [NSThread currentThread]);
};
void (^task3)() = ^() {
NSLog(@"task3----%@", [NSThread currentThread]);
};
dispatch_queue_t serial = dispatch_queue_create("cn.jingcheng", NULL);
dispatch_async(serial, task1);
dispatch_async(serial, task2);
dispatch_async(serial, task3);
}
b.并发队列:
特点:
任务可以同时执行,这样可以提高程序的运行效率.
并发队列,同步任务
特点:没有开辟新线程,同时是按照顺序
应用场景:开发中几乎不用
/**
* 并发队列,同步任务执行
*/
- (void)concurrentSync {
void (^task1)() = ^() {
NSLog(@"task1----%@", [NSThread currentThread]);
};
void (^task2)() = ^() {
NSLog(@"task2----%@", [NSThread currentThread]);
};
void (^task3)() = ^() {
NSLog(@"task3----%@", [NSThread currentThread]);
};
dispatch_queue_t concurrent =
dispatch_queue_create("cn.jingcheng", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(concurrent, task1);
dispatch_sync(concurrent, task2);
dispatch_sync(concurrent, task3);
}
并发队列,异步任务
特点:会开线程,开N条,表示不固定,因为我们的线程循环利用的功能 没有顺序.
应用场景:
比如下载多部片
/**
* 并发队列,异步任务执行
*/
- (void)concurrentAsync {
void (^task1)() = ^() {
NSLog(@"task1----%@", [NSThread currentThread]);
};
void (^task2)() = ^() {
NSLog(@"task2----%@", [NSThread currentThread]);
};
void (^task3)() = ^() {
NSLog(@"task3----%@", [NSThread currentThread]);
};
dispatch_queue_t concurrent =
dispatch_queue_create("cn.jingcheng", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrent, task1);
dispatch_async(concurrent, task2);
dispatch_async(concurrent, task3);
}
c.全局队列:
和并发队列,执行效果一样,只是说,并发队列,需要我们程序员,自己创建
而全局队列,是由于系统提供
特点:
任务可以同时执行,这样可以提高程序的运行效率.
全局队列,同步任务
特点:没有开辟新线程,同时是按照顺序
应用场景:开发中几乎不用
全局队列,异步任务
特点:会开线程,开N条,表示不固定,因为我们的线程循环利用的功能 没有顺序.
应用场景:
比如下载多部片
/**
* 全局队列
*/
- (void)globalQueue{
dispatch_queue_t global = dispatch_get_global_queue(0, 0);
//全局队列同步执行任务
dispatch_sync(global, ^{
NSLog(@"%@",[NSThread currentThread]);
});
//全局队列异步执行任务
dispatch_sync(global, ^{
NSLog(@"%@",[NSThread currentThread]);
});
}
d.主队列(奇葩
):
特点:
它永远在主线程工作,这个是苹果给开发人员,提供,回到主线程做事的一种机制
主队列,同步任务
特点:主队列,只有在`主线程空闲`的时候,才能调度里面的任务
造成死锁
主队列,异步任务
应用场景:
回到主线程做事,一般是做和UI相关的工作.
/**
* 主队列
*/
- (void)mainQueue {
dispatch_queue_t mainQ = dispatch_get_main_queue();
//全局队列同步执行任务 (死锁)
dispatch_sync(mainQ, ^{
NSLog(@"%@", [NSThread currentThread]);
});
//全局队列异步执行任务
dispatch_sync(mainQ, ^{
NSLog(@"%@", [NSThread currentThread]);
});
}
总结:任务的优先级比队列优先级高,所以我们在队列和任务的各种组合的时候,首先要看我们的任务.
1.开不开线程,由任务决定
异步才有开辟线程的能力,同步没有开辟线程的能力
异步是在其它线程上执行,同步,在当前线程上执行.
iOS 8.0 之后,GCD 能够开启非常多的线程
iOS 7.0 以及之前,GCD 通常只会开启 5~6 条线程
2.在开发中,主队列比较奇葩,主队列,就是苹果提供给我们,快速回到主线程的种实现机制.
开发中队列的选择
多线程的目的:将耗时的操作放在后台执行!
串行队列,只开一条线程,所有任务顺序执行
队列组
有这么1种需求
首先:分别异步执行2个耗时的操作
其次:等2个异步操作都执行完毕后,再回到主线程执行操作
如果想要快速高效地实现上述需求,可以考虑用队列组
//创建队列组
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的异步操作都执行完毕后,回到主线程...
});
- (void)cacheStatusImage:(NSArray *)array and:(FinishedArray)finish {
if (array.count == 0) {
finish(nil, nil);
return;
}
//创建线程组
dispatch_group_t group = dispatch_group_create();
for (XFStatues *statues in array) {
NSArray *urls = statues.danLoadPicUrl;
if (urls.count != 1) {
continue;
}
for (NSURL *imageUrl in urls) {
//操作开始
dispatch_group_enter(group);
[[SDWebImageManager sharedManager] downloadImageWithURL:imageUrl
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
}
completed:^(UIImage *image, NSError *error,
SDImageCacheType cacheType, BOOL finished,
NSURL *imageURL) {
NSLog(@"单张图片下载完成");
//操作结束
dispatch_group_leave(group);
}];
}
}
//线程组下载图片任务全部完成,主线程完成所有图片下载回调
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有图片下载完成");
finish(nil, array);
});
}
如果任务有先后执行顺序的要求
效率低 -> 执行慢 -> “省电”
有的时候,用户其实不希望太快!例如使用 3G 流量,”省钱”
并发队列,会开启多条线程,所有任务不按照顺序执行
如果任务没有先后执行顺序的要求
效率高 -> 执行快 -> “费电”
WIFI,包月
实际开发过程中开辟线程数
WIFI 线程数 6 条
3G / 4G 移动开发的时候,2~3条,再多会费电费钱!