IOS开发多线程讲解(一)--结合斯坦福ios7开发(十)
小编之前的文章中有所提及关于网页接口NSURL AND NSURLRequest会阻塞进程的问题,从今天开始到五一假期结束期间,我们来解决关于线程的问题,此处引用的代码以及demo来自斯坦福大学ios7开发课程(十),大学课本《计算机操作系统》以及《Objective-C高级编程》,小编特地做以整合。
一.线程的引入
在OS中引入进程的目的是为了使多个程序能并发执行,以提高资源的利用率和系统的吞吐量,那么,在操作系统中再次引入线程,则是为了减少程序在并发执行时候所付出的时空开销,更好的使OS具有更好的并发性。
为了更好的理解线程,我们先将它放置一边,来看一下他的孪生兄弟--进程
1.进程的两个基本属性
- 进程是一个可以拥有资源的独立单位,一个进程要能独立运行,它必须拥有一定的资源【存放程序正文,数据的磁盘和内存地址空间以及它在运行时候所需要的I/O设备,已打开的文件,信息量等】
-
进程同时又是一个可独立调度和分配等基本单位,一个进程要能独立运行,它必须是一个可独立调度和分配的基本单位
图1--进程
2.程序并发时候所需要的时空开销
Step1:创建进程,创建进程的时候,我们需要进行为进程分配所必须的内存空间,除了cpu以外的所有资源:内存空间,I/O设备以及建立相应的PCB;
Step2:撤销进程,撤销进程时候,需要先释放处理机的所有资源进行回收,再撤销PCB;
Step3:进程切换,进程在进行上下文切换的同时,需要保留当前进程的cpu环境,然后在创建新的cpu环境,这个时候会占有大量的时间空间
综上来看,我们发现了进程在创建,销毁和进程上下文切换后会占用大量的时空开销,为次,引出了线程的概念
二.ios线程的讲解
1.Grand Central Dispatch(GCD)概要
Grand Central Dispatch(GCD)是异步执行的任务的技术之一,一般将应用程序中记述的线程管理用的代码在系统级中实现,开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并执行任务,由于线程管理是作为系统的一部分来实现的,因此可统一管理,也可以执行任务
导入GCD代码展示
dispatch_async(queue,^{
/*长时间处理的任务*/
dispatch_async(dispatch_get_main_queue(),^{
/*只在主线程可以执行的处理
* 例如用户界面更新*/
)};
});
分析:通过异步调用进行处理多线程的问题
- dispatch_async(queue,^{});表示让处理在后台线程中执行
- dispatch_async(dispatch_get_main_queue(),^{});表示让Block内容在主线程中执行
- 在除了主线程的其他队列中,我们主要执行复杂的数据运算与更新,而只在主线程中进行更新用户的UI界面,这样在显示UI界面的同时实现数据的更新和处理,使得宏观上并行操作
2.Dispatch Queue
dispatch_async(queue,^{
/*想要执行的任务*/
});
分析:该源码通过使用Block语法“定义想要执行的任务”,通过dispatch_async函数追加赋值在变量queue的“Dispatch Queue中”,这样就可以使指定的Block在另一个线程中执行
Dispatch Queue --> 执行处理等待队列(先进先出)执行处理
图片2--线程处理顺序
分类:
Dispatch Queue --> 1.Serial Dispatch Queue(等待现在执行中处理)
--> 2.Concurrent Dispatch Queue (不等待现在执行中处理)
示意图


dispatch_async(queue, blk0);
dispatch_async(queue, blk1);
dispatch_async(queue, blk2);
dispatch_async(queue, blk3);
dispatch_async(queue, blk4);
dispatch_async(queue, blk5);
dispatch_async(queue, blk6);
dispatch_async(queue, blk7);
运行结果:顺序执行
blk0;
blk1;
blk2;
blk3;
blk4;
blk5;
blk6;
blk7;
当变量queue为Concurrent Dispatch Queue时候,因为不需要等待现在执行的处理结束,所以首先执行blk0,不管blk0是否结束,都会执行下面的blk1,如此重复下去,直到执行完blk7
因此,我们可以通过示意图理解Concurrent Dispatch Queue使用多个线程,Serial Dispatch Queue使用一个线程

通过对多线程简单了解,我们将概念性的知识点先放在一旁,来通过斯坦福大学的ios7开发部分代码更好的理解一下dispatch_async的应用
NSURLRequest *request = [NSURLRequest requestWithURL:self.imageURL];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *sesstion = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDownloadTask *task = [sesstion downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable locatfile, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
if ([request.URL isEqual:self.imageURL]) {
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:locatfile]];
dispatch_async(dispatch_get_main_queue(), ^{
self.image = image;
});
}
}
}];
[task resume];
分析:- NSURLRequest *request = [NSURLRequest requestWithURL:self.imageURL];通过NSURLRequest来进行网页请求
- NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *sesstion = [NSURLSession sessionWithConfiguration:configuration];通过NSURLSessionConfiguration进行网页配置并且将消息发送给了NSURLSession - 我们通过网页下载作业,将下载的网页保存在locatfile地址中,并且下载成功,我们更新UIImage视图,与此同时,我们的主线程来更新self.image的UI更新
if ([request.URL isEqual:self.imageURL]) {
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:locatfile]];
dispatch_async(dispatch_get_main_queue(), ^{
self.image = image;
});
}