iOS-----使用GCD实现多线程
使用GCD实现多线程
GCD的两个核心概念如下:
|
队列 |
队列负责管理开发者提交的任务,GCD队列始终以FIFO(先进先出)的方式来处理任务---但 由于任务的执行时间并不相同,因此先处理的任务并一定先结束。队列既可是串行队列,也可是并发队列则可同时处理多个任务,因此将会有多个任务并发执行。 队列底层会维护一个线程池来处理用户提交的任务,线程池的作用就是执行队列管理的任务。串行队列底层的线程池只要维护一个线程即可,并发队列的底层则需要维护多个线程。 |
|
|
任务 |
任务就是用户提交给队列的工作单元,这些任务将会提交给队列底层维护的线程池执行,因此这些任务会以多线程的方式执行。 |
|
|
使用GCD只要遵守两个步骤即可 |
||
|
1. |
创建队列 |
|
|
2. |
将任务提交给队列 |
|
创建队列
|
GCD的队列可分为两种 |
||
|
串行队列 |
串行队列底层的线程只要一个线程,因此只提供一个线程用来执行任务,所以后一个任必须等到前一个任务执行结束才能开始执行 |
|
|
并发队列 |
线程池提供多个线程来执行任务,所以可以按FIFO(先进先出)的顺序并发启动、执行多个并发任务。 |
|
|
函数 |
||
|
涉及一个dispatch_queue_t,这种类型就代表一个队列。 |
||
|
程序可以创建如下几种队列 |
||
获取系统默认的全局并发队列可通过如下代码完成: dispatch_queue_t queue = dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
获取系统主线程关联的串行队列可通过如下代码完成: dispatch_queue_t queue = dispatch_get_main_queue(); 如果将任务提交给主线程关联的串行队列,那么就相当于直接在程序主线程中去执行该任务。
创建串行队列可通过如下代码完成: dispatch_queue_t queue = dispatch_queue_create(“LCiOS.queue”, DISPATCH_QUEUE_SERIAL); 如果将多个任务提交给串行队列,多个任务只能按顺序执行,必须等前一个任务完成后,才能开始执行后一个任务。
创建并发队列可通过如下代码完成: dispatch_queue_t queue = dispacth_queue_create(“LCiOS.queue” , DISPATCH_QUEUE_CONCURRENT); 如果将多个任务提交给并发队列,并发队列可以按FIFO(先进先出)的顺序启动多个并发执行的任务,由于任务的耗时长短并不相同,因此后提交的任务完全可能先完成。 得到队列之后,接下来就可以将任务提交给队列,并由队列底层管理的线程池来执行这些任务。 |
||
异步提交任务
iOS提供了如下函数来向队列提交任务。下面这些函数很多都有两个版本:一个接收代码块作为参数的版本,
一个接收函数作为参数的版本----其中接收函数作为参数的函数名最后多了_f后缀,而且会多一个参数,用于向函数传入应用程序定义的上下文。
|
代 码 片 段 |
ViewController.m
@implementation ViewController
// 定义2个队列
dispatch_queue_t serialQueue;
dispatch_queue_t concurrentQueue;
- (void)viewDidLoad
{
[super viewDidLoad];
// 创建串行队列
serialQueue = dispatch_queue_create(“LCiOS.queue”,DISPATCH_QUEUE_SERIAL);
// 创建并发队列
concurrentQueue = dispatch_queue_create(“LCiOS.queue”,DISPATCH_QUEUE_CONCURRENT);
}
- (IBAction)serial:(id)sender
{
// 依次将两个代码块提交给串行队列
// 必须等到第1个代码块完成后,才能执行第2个代码块
dispatch_async(serialQueue, ^(void)
{
for(int i = ; i < ; i++)
{
NSLog(@”%@====%d”, [NSThread currentThread], i);
}
});
dispatch_async(serialQueue, ^(void)
{
for(int i = ; i < ; i++)
{
NSLog(@”%@-----%d”, [NSThread currentThread], i);
}
});
}
- (IBAction)concurrent:(id)sender
{
// 依次将两个代码块提交给并发队列
// 两个代码块可以并发执行
dispatch_async(concurrentQueue, ^(void)
{
for(int i = ; i < ; i ++)
{
NSLog(@”%@====%d”, [NSThread currentThread] , i);
}
});
dispatch_async(concurrentQueue, ^(void)
{
for(int i = ; i < ; i ++)
{
NSLog(@”%@-----%d”, [NSThread currentThread] , i);
}
});
}
@end
|
|
说 明 |
上面程序中的两行粗体字代码创建了两个队列,其中第1个队列是串行队列,第2个队列是并发队列。接下来程序实现了serial:和concurrent:两个事件处理方法,在serial:方法中使用dispatch_async()函数向串行队列以异步方式提交两个代码块,在concurrent:方法中使用dispatch_async()函数向并发队列以异步方式提交两个代码块。 编译、运行该程序,如果用户单击的按钮控制程序向串行队列提交两个代码块,将可以在控制台看到如下图所示的输出。 如果 如果用户单击的按钮控制程序向并发队列提交两个代码块,将可以在控制台看到如下图所示的输出 |
|
使用G CD下载图片 |
ViewController.m
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)downImag:(id)sender
{
// 将代码块提交给系统的全局并发队列
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH , ) , ^(void){
NSString* url = @” http://images.cnblogs.com/cnblogs_com/congli0220/752817/o_%e4%b8%8b%e8%bd%bd.jpg”;
// 从网络获取数据
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
// 将网络数据初始化为UIImage对象
UIImage *image = [[UIImage alloc] initWithData:data];
if(image != nil)
{
// 将代码块提交给主线程关联的队列,该代码将会由主线程完成
dispatch_async(dispatch_get_main_queue(), ^{
self.iv.image = image;
});//
}
else
{
NSLog(@”---下载图片出现错误---”);
}
});
}
@end
|
|
说明 |
该程序中的代码会将代码块提交给系统默认的全局并发队列,该代码块就会负责从网络下载图片。由于该代码块同样会在多线程中执行,因此程序的“1”号代码处再次使用了dispatch_async()函数将更新界面上UI控件的代码交给主线程执行. |
同步提交任务
dispatch_sync()函数则会以同步方式提交代码块,该函数必须等到代码块执行结束才会返回.如果程序使用该函数先后提交了两个代码块(即使提交给并发队列),也必须等第1个任务完成后才会开始执行第2个任务.
|
例如如下示例的视图控制器类的实现部分代码 |
|
|
代 码 片 段 |
ViewController.m
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)clicked:(id)sender
{
// 以同步方式先后提交两个代码块
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^(void){
for(int i = ; i < ; i++)
{
NSLog(@”%@====%d”, [NSThread currentThread] , i);
[NSThread sleepForTimeInterval:0.1];
}
});
// 必须等第1次提交的代码块执行完成后,dispatch_sync()函数才会返回
// 程序才会执行到这里,才能提交第2个代码块
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^(void){
for(int i = ; i < ; i ++)
{
NSLog(@”%@------%d”, [NSThread currentThread] , i);
[NSThread sleepForTimeInterval:0.1];
}
});
}
@end
|
|
说明 |
上面程序使用dispatch_sync()函数以同步方式提交代码块,该函数必须等到所提交的代码块执行完成后才会返回,因此该函数虽然启动另外的线程来执行代码块,但它依然会阻塞主线程. 上面程序先后两次使用dispatch_sync()函数来提交代码块,因此程序必须等到第1次使用dispatch_sync()函数提交的代码块执行完成后,该函数才会返回,程序才会执行第2次提交. 只有等到两次提交的代码块都执行完成后,clicked:事件处理方法才能返回----表明事件响应执行完成.如果用户单击激发该事件的按钮,该按钮将会一直处于高亮状态,直到两个代码块执行完成 |
多次执行的任务
dispatch_apply()函数将控制提交的代码块重复执行多次,如果该代码块被提交给并发队列,系统可以使用多个线程并发执行同一个代码块.
下面示例程序在界面上包含了一个按钮,当用户单击该按钮时将会使用dispatch_apply()函数将代码块提交给并发队列,并控制该代码块执行多次.
下面是该示例的视图控制器类的实现部分代码.
|
代 码 片 段 |
ViewController.m
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)clicked:(id)sender
{
// 控制代码执行5次
dispatch_apply( , dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, )
// time形参代表当前正在执行第几次
,^(size_t time)
{
NSLog(@===执行【%lu】次===%@”, time , [NSThread currentThread]);
});
}
@end
|
|
说明 |
上面程序中的粗体字代码使用dispatch_apply()函数控制提交的代码块执行5次,该函数所需的代码块略有不同,该代码块可以带一个参数,该参数代表当前正在执行第几次. |
只执行一次的任务
dispatch_once()函数将控制提交的代码块在整个应用的生命周期内最多只执行一次----只有第1次提交该代码块时,
该代码块才会获得执行的机会.而且dispatch_once()函数无须传入队列,这意味着系统将直接用主线程执行该函数提交的代码块.
dispatch_once()函数执行时需要传入一个dispatch_once_t类型(本质就是long型整数)的指针(即predicate参数),
该指针变量用于判断该代码块是否已经执行过.
下面示例程序在界面上包含了一个按钮,当用户单击该按钮时激发的事件处理方法将会使用dispatch_once()函数提交代码块,
将代码块提交给主线程执行,因此该代码块可能阻塞主线程.但当用户再次单击该按钮时,dispatch_once()函数提交的代码块不会再执行.
|
代码片段 |
ViewController.m
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)clicked:(id)sender
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@”==执行代码块==”);
// 线程暂停3秒
[NSThread sleepForTimeInterval:];
});
}
@end
|
iOS-----使用GCD实现多线程的更多相关文章
- iOS的三种多线程技术NSThread/NSOperation/GCD
1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心 ...
- iOS开发中GCD在多线程方面的理解
GCD为Grand Central Dispatch的缩写. Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法.在Mac OS X 10.6雪豹中 ...
- iOS开发——GCD多线程详解
GCD多线程详解 1. 什么是GCD Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,简单来说,GCD就是iOS一套解决多线程的机制,使用GCD能够最大限度简化多线程 ...
- Objective-C 高级编程:iOS与OS X多线程和内存管理
<Objective-C 高级编程:iOS与OS X多线程和内存管理> 基本信息 原书名: Pro Multithreading and Memory Management for iOS ...
- IOS开发 GCD介绍: 基本概念和Dispatch Queue
iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题 ØN ...
- iOS开发网络篇—多线程断点下载
iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始, ...
- GCD与多线程
GCD与多线程 GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制.它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务. GCD中的 ...
- iOS's GCD Note
[iOS's GCD Note] 1.默认有四种全局concureent queue,如下: 通过以下函数来引用: 2.官方文档上并发队列有3种,实际上main就是serial. 1)serial,用 ...
- apple平台下的objc的GCD,多线程编程就是优雅自然。
在apple的操作系统平台里,GCD使得多线程编程是那么的优雅自然.在传统的多线程编程中,首先要写线程处理循环:之后还有事件队列,消息队列:还要在线程循环中分离事件解释消息,分派处理:还要考虑线程间是 ...
随机推荐
- Selenium之firefox浏览器的启动
1.编写如下代码 import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; /** ...
- (24)如何使用HttpClient
介绍 HttpClient是HTTP客户端的接口.HttpClient封装了各种对象,处理cookies,身份认证,连接管理等. 概念 HttpClient的使用一般包含下面6个步骤: 创建 Http ...
- VS2010/MFC编程入门之二十七(常用控件:图片控件Picture Control)
上一节中鸡啄米讲的是滚动条控件,本节主要讲一种简单实用的控件,图片控件Picture Control.我们可以在界面某个位置放入图片控件,显示图片以美化界面. 图片控件简介 图片控件和前面讲到的静态文 ...
- Ubuntu软件包管理器
Ubuntu软件包管理 Ubuntu下对软件管理工具有:apt,dpkg,tasksel,aptitude等,我们常用的就是前三个工具.下面就介绍这三个工具的用法. dpkg 在Linux发展之初,安 ...
- python 解析xml遇到xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 4, column 34
在调试数字驱动用xml文件的方式时,包含读取xml文件的步骤,运行程序报错: d:\test\0629>python XmlUtil.pyTraceback (most recent call ...
- ubuntu下 adb devices找不到devices
不同手机用数据线与ubuntu连接后,执行adb devices,好多出现找不到devices的情况. 这里解决措施: 1. 执行lsusb(连接手机前与后) 找到显示内容的差异项: root@loc ...
- 自动化运维工具SaltStack安装配置
SaltStack是一种全新的基础设置管理方式,部署轻松,在几分钟内可运作起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯.通过部署SaltStack环境,我们可以在成千上万台服务 ...
- Java Mail 邮件发送简单封装
上一篇文章我们用写了一个Java Mail 的Demo,相信你已经可以用那个例子来发送邮件了.但是Demo 有很多的问题. 首先每次发送需要配置的东西很多,包括发件人的邮箱和密码.smtp服务器和SM ...
- 【问题解决:未找到端口号】启动报错Circular placeholder reference 'server.port' in property definitions
问题描述: 启动spring boot项目时报错:Circular placeholder reference 'server.port' in property definitions 解决过程: ...
- hdu 5687 Problem C trie树
Problem C Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Prob ...