多线程(2) - ios关于线程调度的三种方式之GCD
GCD(链接:http://blog.csdn.net/linzhiji/article/details/6863972)
一 概念和理解
Grand Central Dispatch(多线程的优化技术)GCD
是一套底层API,基于C语言开发的多线程机制,提供了新的模式编写并发执行的程序。
特点:
1.允许将一个程序切分为多个单一任务,然后提交到工作队列中并发或者串行地执行
2.为多核的并行运算提出了解决方案,自动合理的利用CPU内核(比如双核,四核)
3.自动的管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,只需要告诉它任务是什么就行
4.配合Block,使得使用起来更加方便灵活
2.什么是Queue队列?
GCD使用了队列的概念,解决了NSThread难于管理的问题,队列实际上就是数组的概念,通常我们把要执行的任务放到队列中管理
特点:
1.按顺序执行,先进先出
2.可以管理多线程,管理并发的任务,设置主线程
3.GCD的队列是任务的队列,而不是线程的队列
3.什么是任务?
任务即操作:你想要干什么,说白了就是一段代码,在GCD中,任务就是一个block
任务的两种执行方式:
同步执行:只要是同步任务,都会在当前的线程执行,不会另开线程
异步执行:只要是异步任务,都会开启新线程,在开启的线程中执行
4.什么是串行队列?
依次完成每一任务
5.什么是并行队列?
好像所有的任务都是在同一时间执行的
6.都有哪些队列?
Main Queue(主队列,串行);全局队列(Global Queue);自己创建的队列(Queue)
从上面的概念以及gcd所解决的问题来看,使用GCD的时候就要开始转变观念了。现在我们需要考虑的只是任务,队列,队列间同步或异步的关系了。而不是考虑怎么开辟线程,怎么管理线程,所有关于线程的东西,我们都不需要考虑。整个程序完全就是由队列来自动管理了。首先,整个程序是由全局队列来管理,然后UI的刷新是由mainqueue管理,我们可以将我们的任务放到我们创建的队列中去,也可以放在主队列中,也可以放在全局队列中。
举个例子:现在我们要从网络上下载一张图片,可以直接将任务放到主队列中去执行,但是这样会出项一个问题,因为主队列是处理和UI相关的任务的,所以在创建(或者刷新)UI的时候,界面就会卡住,直到这张图片现在完毕。所以一般的做法是首先获取全局队列,然后在全局队列中植入下载图片的代码,在下完成后,将图片刷回UI,也就是主队列。至于图片什么时候下载完毕,怎么开辟线程,我们都不需要管。需要做的就是处理代码逻辑就行。以下是使用GCD下载图片的代码
+ (void)SL_setImageView:(UIImageView *)imageView url:(NSString *)url
{
//对应全局队列开启一个异步任务
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//下载图片数据
NSURL *imageURL = [NSURL URLWithString:url];
NSData *data = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:data];
//刷新ImageView (回调主线程)
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = image;
});
});
}
关于容易混淆概念的区分:
1, 同步,异步,串行,并发
同步和异步代表会不会开辟新的线程。串行和并发代表任务执行的方式。
同步串行和同步并发,任务执行的方式是一样的。没有区别,因为没有开辟新的线程,所有的任务都是在一条线程里面执行。
异步串行和异步并发,任务执行的方式是有区别的,异步串行会开辟一条新的线程,队列中所有任务按照添加的顺序一个一个执行,异步并发会开辟多条线程,至于具体开辟多少条线程,是由系统决定的,但是所有的任务好像就是同时执行的一样。
开辟队列的方法:
dispatch_queue_t myQueue = dispatch_queue_create("MyQueue", NULL);
/**
参数1:标签,用于区分队列
参数2:队列的类型,表示这个队列是串行队列还是并发队列NUll表示串行队列,
DISPATCH_QUEUE_CONCURRENT表示并发队列
*/
执行队列的方法
异步执行
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
同步执行
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)
二,主队列
主队列:专门负责调度主线程度的任务,没有办法开辟新的线程。所以,在主队列下的任务不管是异步任务还是同步任务都不会开辟线程,任务只会在主线程顺序执行。
主队列异步任务:现将任务放在主队列中,但是不是马上执行,等到主队列中的其它所有除我们使用代码添加到主队列的任务的任务都执行完毕之后才会执行我们使用代码添加的任务。
主队列同步任务:容易阻塞主线程,所以不要这样写。原因:我们自己代码任务需要马上执行,但是主线程正在执行代码任务的方法体,因此代码任务就必须等待,而主线程又在等待代码任务的完成好去完成下面的任务,因此就形成了相互等待。整个主线程就被阻塞了。
三,全局队列
全局队列:本质是一个并发队列,由系统提供,方便编程,可以不用创建就直接使用。
获取全局队列的方法:dispatch_get_global_queue(long indentifier.unsigned long flags)
/**
参数说明:
参数1:代表该任务的优先级,默认写0就行,不要使用系统提供的枚举类型,因为ios7和ios8的枚举数值不一样,使用数字可以通用。
参数2:苹果保留关键字,一般也写0
*/
全局队列和并发队列的区别:
1,全局队列没有名字,但是并发队列有名字。有名字可以便于查看系统日志
2,全局队列是所有应用程序共享的。
3,在mrc的时候,全局队列不用手动释放,但是并发队列需要。