GCD纯C语言实现的,提供了非常多而且强大的函数,可以调高我们的代码的执行效率和多核利用率,ios4后引入的新一代多线程编程技术。
特点:
- 1 由苹果公司为多核的并行运算提出的解决方案
- 2 它会自动利用更多的处理器核心
- 3 不用关心线程代码,GCD会负责创建线程和调度任务
使用步骤:
- 1 制定任务
- 2 把任务添加到适当的队列中
说明:GCD会自动的将队列中的任务取出,放到对应的线程中执行
区分名词
同步异步
同步和异步是相对于另外一个任务而言的。
同步:在当前线程执行,第一个任务不执行完,第二个任务不会开始
异步:在另一条线程中执行,不管第一个有没有执行完,都会开始第二个
并发并行
并发说的是多任务,并行说的是多线程,并行要求并发,并发并不能保证并行(单核)
并发和串行队列
并发和串行是相对于多个任务而言的。
** 并发队列** : 在异步的情况下,多个任务并发执行。
串行队列 : 多个任务会按照顺序执行。串行队列用于管理共享资源是极好的。它保证了序列化访问共享资源,防止了竞态条件。想象一个售票亭,有一群人想买电影票,这里的展台的工作人员就是一个共享资源。如果员工需要为这些人在同一时间服务,这将是混乱的。为了处理这种情况,人们需要排队(串行队列),这样员工可以一次服务一个顾客。同时,设置多个窗口多个多个排队也属于串行的一种。
有以下几种组合:
-
- 串行队列同步执行:综合上面阐述的串行队列的特点 --- 按顺序执行,同步:不会开启新的线程,则串行队列同步执行只是按部就班的one by one执行。特点:不会开辟新线程,任务按照顺序执行。
-
- 串行队列异步执行:虽然队列中存放的是异步执行的任务,但是结合串行队列的特点,前一个任务不执行完毕,队列不会调度,所以串行队列异步执行也是one by one的执行。特点:会创建新线程(只有一个),任务按照顺序执行。优点:不会卡死,任务顺序执行的话方便调试,缺点:只开一个线程,并发性不强。
-
- 并行队列同步执行:结合上面阐述的并行队列的特点,和同步执行的特点,可以明确的分析出来,虽然并行队列可以不需等待前一个任务执行完毕就可调度下一个任务,但是任务同步执行不会开启新的线程,所以任务也是one by one的执行。
*4.并行队列异步执行:再上一条中说明了并行队列的特点,而异步执行是任务可以开启新的线程,所以这中组合可以实现任务的并发,再实际开发中也是经常会用到的。特点:会新建多个线程(由系统自己决定),任务是无序的(有用,但是容易出错), 优点:相对于串行队列的异步任务,并发性更好。
- 并行队列同步执行:结合上面阐述的并行队列的特点,和同步执行的特点,可以明确的分析出来,虽然并行队列可以不需等待前一个任务执行完毕就可调度下一个任务,但是任务同步执行不会开启新的线程,所以任务也是one by one的执行。
-
- 主队列:专门用来在主线程调度任务的队列,所以主队列的任务都要在主线程来执行,主队列会随着程序的启动一起创建,我们只需get即可。
队列和任务的特点:
队列的特点:先进先出,排在前面的任务最先执行,
全局队列:后台并发执行。
主队列:主线程串行执行。
串行队列:任务按照顺序被调度,前一个任务不执行完毕,队列不会调度
并行队列:只要有空闲的线程,队列就会调度当前任务,交给线程去执行,不需要考虑前面是都有任务在执行,只要有线程可以利用,队列就会调度任务。
各队列类型代码实现:
以加载图片为例,首先初始化几个图片资源:
@property (nonatomic,copy)NSString *imgUrl1;
@property (nonatomic,copy)NSString *imgUrl2;
@property (nonatomic,copy)NSArray *imgArray;
imgUrl1 = @"https://raw.githubusercontent.com/minggo620/iOSMutipleThread/master/picture/multiplethread2.jpeg";
imgUrl2 = @"https://raw.githubusercontent.com/minggo620/iOSRuntimeLearn/master/picture/gongzhonghao.jpg";
imgArray = @[@"04.png",@"headImage",@"cup.jpg",@"headImage",@"04.png",@"cup.jpg"];
-(void)loadImageSource:(NSString *)url{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [UIImage imageWithData:imgData];
if (imgData!=nil) {
[self.imageview1 setImage:image];
}else{
NSLog(@"there no image data");
}
}
全局队列加载图片(dispatch_get_global_queue)
后台执行(全局并行队列,有四个优先级:
DISPATCH_QUEUE_PRIORITY_HIGH 2
DISPATCH_QUEUE_PRIORITY_DEFAULT 0
DISPATCH_QUEUE_PRIORITY_LOW (-2)
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN)
-(void)globalQueue{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self loadImageSource:imgUrl1];//添加图片view,加载图片
});
}
主线程加载图片(dispatch_get_main_queue)
UI线程执行(mainQueue会插入主线程的runloop中执行,显然是串行队列,用来更新UI)
-(void)mainQueue{
dispatch_async(dispatch_get_main_queue(), ^{
[self loadImageSource:imgUrl1];
});
}
一次性线程执行(dispatch_once_t)
常用来写单例
-(void)dispatchOnce{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:NULL] init];
});
return instance;
}
并发执行循环迭代(dispatch_apply)
dispatch_apply函数是dispatch_sync函数和Dispatch Group的关联API,该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等到全部的处理执行结束
它一般都是放在dispatch_async里面(异步),dispatch_apply如果换成串行队列上,则会依次执行,但这样违背了我们想并行提高执行效率的初衷。
-(void)dispatchApply{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
size_t count = 10;
dispatch_async(queue, ^(){
dispatch_apply(count, queue, ^(size_t i) {
NSLog(@"循环执行第%li次",i);
if (i == 9) {
[self loadImageSource:imgUrl1];
NSLog(@"存在的");
};
});
});
}
后台异步加载多张图片
-(void)globalQueue2{
//异步必并发
//并行的并发执行(异步的)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//后台并发异步加载图片
UIImage *image1 = [self loadImage:imgUrl1];
UIImage *image2 = [self loadImage:imgUrl2];
//显然是串行队列,用来更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"ui显示");
self.imageview1.image = image1;
self.imageView2.image = image2;
});
});
}
并发线程组加载执行多任务(dispatch_get_global_queue,dispatch_group_notify)
-(void)dispatchGroup{
//优先级为0---并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//并行多任务群发异步事件发生顺序随机
dispatch_async(queue, ^{
//群发队列
dispatch_group_t group = dispatch_group_create();
__block UIImage *image1 = nil;
__block UIImage *image2 = nil;
//异步全局队列
dispatch_group_async(group, queue, ^{
image1 = [self loadImage:imgUrl1];
NSLog(@"异步全局队列1");
});
//异步全局队列
dispatch_group_async(group, queue, ^{
image2 = [self loadImage:imgUrl2];
NSLog(@"异步全局队列2");
});
//群发队列执行完毕回到主线程刷新UI
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
self.imageview1.image = image1;
self.imageView2.image = image2;
});
});
}
延迟执行(dispatch_after)
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){
UIImage *image = [self loadImage:imgUrl2];
self.imageView2.image = image;
});
```
####总结:理解GCD首先就是弄懂了各种线程队列的触发和执行顺序,接着代码实现逐步分析就很好理解了,个人理解希望对你们有所帮助,有不足之处也希望多多指教。