GCD多线程
1.什么是GCD?
全称是Grand Central Dispatch
纯C语言,提供了非常多强大的函数
2.GCD的优势
GCD为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
二、任务和队列
GCD中有2个核心概念
(1)任务:执行什么操作
(2)队列:用来存放任务
GCD的使用就2个步骤
(1)定制任务
(2)确定想做的事情
将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行
提示:任务的取出遵循队列的FIFO原则:先进先出,后进后出
三、执行任务
1.GCD中有2个用来执行任务的函数
说明:把右边的参数(任务)提交给左边的参数(队列)进行执行。
(1)用同步的方式执行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
参数说明:
queue:队列
block:任务
(2)用异步的方式执行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
2.同步和异步的区别
同步:在当前线程中执行
异步:在另一条线程中执行
1.队列的类型
GCD的队列可以分为2大类型
(1)并发队列(Concurrent Dispatch Queue)
可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效
(2)串行队列(Serial Dispatch Queue)
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
2.补充说明
有4个术语比较容易混淆:同步、异步、并发、串行
同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此参数暂时无用,用0即可
示例:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列
//下面是方法的具体实现
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView*imageview=[[UIImageView alloc]initWithFrame:CGRectMake(30, 40, 100, 100)];
[self.view addSubview:imageview];
UIImageView*imageview1=[[UIImageView alloc]initWithFrame:CGRectMake(30, 150, 100, 100)];
[self.view addSubview:imageview1];
UIImageView*imageview2=[[UIImageView alloc]initWithFrame:CGRectMake(30, 260, 100, 100)];
[self.view addSubview:imageview2];
UIImageView*imageview3=[[UIImageView alloc]initWithFrame:CGRectMake(30, 260, 100, 100)];
[self.view addSubview:imageview3];
UIImageView*imageview4=[[UIImageView alloc]initWithFrame:CGRectMake(30, 260, 100, 100)];
[self.view addSubview:imageview4];
//第一种方法
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//这里面执行耗时操作
NSData*data=[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.yooyoo360.com/photo/2009-1-1/20090112132752467.jpg"]];
UIImage*image=[UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
//这里面更新ui
imageview.image=image;
});
});
//第二种方法
//第二种方法,创建一个组:用于存放耗时操作
//将操作封装进组,第一个参数代表要存放操作的组名,第二个参数代表操作队列,block执行耗时操作
dispatch_group_t group=dispatch_group_create();
__block UIImage*image1,*image2,*image3;
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSData*data=[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic2.ooopic.com/10/81/58/62bOOOPICce.jpg"]];
image1=[UIImage imageWithData:data];
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSData*data=[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.downsc.com/vector_pic/shiliang_iecool/5/3/b_img/14430.jpg"]];
image2=[UIImage imageWithData:data];
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSData*data=[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.downsc.com/vector_pic/shiliang_iecool/5/2/b_img/13788.jpg"]];
image3=[UIImage imageWithData:data];
});
//监听一组操作,第一个参数代表要监听的组名,第二个参数代表一组操作完全结束后跳转到哪个队列,一般跳到主线程(dispatch_get_main_queue),block执行要进行的操作(一般用来更新UI),注意:此方法在组中的所有操作执行完毕后调用
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
imageview2.image=image1;
imageview3.image=image2;
imageview4.image=image3;
});