IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习
介绍:前面内容源自网络
Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。
练习简介:点击ok按钮就会计算从1-很大的数的和,不用多线程就会出现假死状态,其他操作不能执行,现在用多线程解决这个问题
注意:(Dispatch queue启动时默认状态是挂起的,我们创建完毕之后得主动恢复,否则事件不会被传送)
设计:
GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行
dispatch queue分为下面三种:
Serial
又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
Concurrent
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
Main dispatch queue
它是全局可用的serial queue,它是在应用程序主线程上执行任务的。
我们看看dispatch queue如何使用
1、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- // 耗时的操作
- dispatch_async(dispatch_get_main_queue(), ^{
- // 更新界面
- });
- });
如果这样还不清晰的话,那我们还是用上两篇博客中的下载图片为例子,代码如下:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];
- NSData * data = [[NSData alloc]initWithContentsOfURL:url];
- UIImage *image = [[UIImage alloc]initWithData:data];
- if (data != nil) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.imageView.image = image;
- });
- }
- });
运行显示:
是不是代码比NSThread NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。
系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:
- dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
这里也用到了系统默认就有一个串行队列main_queue
- dispatch_queue_t mainQ = dispatch_get_main_queue();
虽然dispatch queue是引用计数的对象,但是以上两个都是全局的队列,不用retain或release。
2、dispatch_group_async的使用
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_group_t group = dispatch_group_create();
- dispatch_group_async(group, queue, ^{
- [NSThread sleepForTimeInterval:1];
- NSLog(@"group1");
- });
- dispatch_group_async(group, queue, ^{
- [NSThread sleepForTimeInterval:2];
- NSLog(@"group2");
- });
- dispatch_group_async(group, queue, ^{
- [NSThread sleepForTimeInterval:3];
- NSLog(@"group3");
- });
- dispatch_group_notify(group, dispatch_get_main_queue(), ^{
- NSLog(@"updateUi");
- });
- dispatch_release(group);
dispatch_group_async是异步的方法,运行后可以看到打印结果:
2012-09-25 16:04:16.737 gcdTest[43328:11303] group1
2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2
2012-09-25 16:04:18.738 gcdTest[43328:13003] group3
2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi
每个一秒打印一个,当第三个任务执行后,upadteUi被打印。
这个group如此写是无法显示ui 的,以下是解决方案
- (IBAction)onClickDispatchCancel:(id)sender {
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(self.gcd_group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"yes";
});
});
dispatch_group_async(self.gcd_group, queue, ^{
[NSThread sleepForTimeInterval:1];
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"hello";
});
});
dispatch_group_async(self.gcd_group, queue, ^{
[NSThread sleepForTimeInterval:2];
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"ok";
});
});
dispatch_group_notify(self.gcd_group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"finished";
});
});
}
每一个里面都加上了dispatch_async(dispatch_get_main_queue(),只有在主线程里才会更新ui的显示.这里我遇到过一个崩溃,而且xcode不给提示原因是最后一句我写成了 dispatch_group_notify(self.gcd_group, queue, ^{
self.textField.text=@"finished";
});
所以不仅不显示,而且结果是程序崩溃.所以显示ui更新的时候就要进入主线程.
3、dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:
- dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
- dispatch_async(queue, ^{
- [NSThread sleepForTimeInterval:2];
- NSLog(@"dispatch_async1");
- });
- dispatch_async(queue, ^{
- [NSThread sleepForTimeInterval:4];
- NSLog(@"dispatch_async2");
- });
- dispatch_barrier_async(queue, ^{
- NSLog(@"dispatch_barrier_async");
- [NSThread sleepForTimeInterval:4];
- });
- dispatch_async(queue, ^{
- [NSThread sleepForTimeInterval:1];
- NSLog(@"dispatch_async3");
- });
打印结果:
2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async
2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3
请注意执行的时间,可以看到执行的顺序如上所述。
4、dispatch_apply
执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
// 执行5次
});
//练习:
一,界面设计,两个按钮一个文本框
1,声明线程属性:@property (nonatomic,strong) NSThread *thread;
2,重写get方法:
-(NSThread *)thread
{
if (_thread!=nil) {
return _thread;
}
_thread=[[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
return _thread;
}
3,实现部分
-(void)threadMethod
{
long long sum=self.textView.text.longLongValue;
for (long long i=0; i<=45000; i++) {
if ([self.thread isCancelled]) {//如果线程是取消状态就要把线程销毁,否则再次执行的时候会崩溃
self.thread=Nil;//释放内存
[NSThread exit];//销毁线程
}
[self performSelectorOnMainThread:@selector(refresh:) withObject:@(sum).description waitUntilDone:YES];
sum+=i;
}
self.thread = nil;//这地方如果不销毁线程,当程序计算执行完之后再次点击ok按钮就会出现程序崩溃
}
-(void)refresh:(id)sender
{
self.textView.text=sender;
NSLog(@"refresh");
}
- (IBAction)onClickStart:(id)sender {
if ([self.thread isExecuting]) {//如果程序正在执行就直接返回,否则会出错
return;
}
// NSLog(@"%@",[NSThread currentThread]);
[self.thread start];
}
- (IBAction)onClickCancel:(id)sender {
if ([self.thread isExecuting]) {//如果程序正在执行就执行取消操作,如果没有这个判断,结果是:点击两次取消按钮,在点击ok按钮就会崩溃
[self.thread cancel];
}
}
2,用NSOperationQueue方式来实现
- (IBAction)onClickOperationBegin:(id)sender {
if (self.queue.operationCount>=1)
{
return;
}
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(queueMethod) object:nil];
[self.queue addOperation:operation];
[self.queue setSuspended:NO];
}
- (IBAction)onClickOperationCancel:(id)sender {
[self.queue setSuspended:YES];
}
-(void)queueMethod
{
long long sum=self.textField.text.longLongValue;
for (long long i=0; i<23453; i++) {
if ([self.queue isSuspended]) {
return;
}
[self performSelectorOnMainThread:@selector(refreshThread:) withObject:@(sum).description waitUntilDone:YES];
sum+=i;
}
[self.queue setSuspended:YES];
}
3,dispatch方式的实现(停止功能没实现,欢迎供稿)
- (IBAction)onClickDispatchBegin:(id)sender {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
usleep(200);
long long sum=self.textField.text.longLongValue;
for (long long i=0; i<35457; i++)
{
usleep(200);
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@(sum).description;
});
sum+=i;
}
});
}
IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习的更多相关文章
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
http://blog.csdn.net/totogo2010/article/details/8016129 GCD很好的博文
- iOS 多线程编程之Grand Central Dispatch(GCD)
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...
- Grand Central Dispatch (GCD)
Grand Central Dispatch (GCD) Reference Grand Central Dispatch (GCD) comprises language features, run ...
- 深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
- [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
- iOS 中NSOperationQueue,Grand Central Dispatch , Thread的上下关系和区别
In OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central D ...
- iOS开发之再探多线程编程:Grand Central Dispatch详解
Swift3.0相关代码已在github上更新.之前关于iOS开发多线程的内容发布过一篇博客,其中介绍了NSThread.操作队列以及GCD,介绍的不够深入.今天就以GCD为主题来全面的总结一下GCD ...
- Grand Central Dispatch(GCD)详解(转)
概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...
随机推荐
- hdu-------1081To The Max
To The Max Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- linux查看是否已安装GCC及安装GCC
输入:gcc -v;如果提示未找到命令即表示没有安装 使用:yum install gcc即可
- linq to xml学习
http://www.cnblogs.com/greatverve/archive/2010/07/09/linq-to-xml-add-delete-update-query.html 记录一下,别 ...
- caches 文件夹删除
模拟器 可以 删除 真机不行
- socket编程概述
一.基本流程如下: 整个TCP过程非常类似于电话系统.TCP是有两个不同主机上的进程需要进行通信,电话系统是有两个人位于不同地区的人需要进行通信. socket:获得可用于进程通信的端点.由于Linu ...
- javaNIO是什么?由那几部分组成?各部分的作用。
Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Sel ...
- 如何获取google可以访问的IP地址
由于某些原因,google的部分网站无法打开,导致我们的好些资源都无法找到,今天在网上看到一篇文件,教大家如何能找到可以访问的google. 假如我们需要访问的是:https://code.googl ...
- SSH(1)
假定服务器ip为192.168.1.139,ssh服务的端口号为22,服务器上有个用户为pi,两边都是ubuntu 一,Init *安装 如果是想用ssh从本机登陆别的机器,只需要安装openssh- ...
- mysql 导入数据库文件到指定数据库
i:\mysql\bin>mysql -u 用户名 -p 数据库名 < i:/test.sql // (source "c:\adsense.sql" ) ...
- InterruptedException 线程异常
InterruptedException 这个异常一般发生在线程中,当一个正在执行的线程被中断时就会出现这个异常-! 简单的说就是:假如有两个线程,第一个线程正在运行,第二个没有运行,这时第二个线程启 ...