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就能生成必要的线程并计划执行任务.由于 ...
随机推荐
- WPF:ListView数据绑定及Style
DrugRecordsWin.xaml <ListView Grid.Row="4" Grid.Column="1" Name="list_Dr ...
- servlet 配置
<servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.web.s ...
- IntelliJ IDEA 12 与 Tomcat 集成并运行Web项目
配置Tomcat Server 1.Ctrl+Alt+s或者File——>Setting...;选中“Application Servers”点击"+" 创建运行配置 上面的 ...
- BZOJ1576 [Usaco2009 Jan]安全路经Travel
首先用Dijkstra做出最短路生成树,设dis[p]为1到p点的最短路长度 对于一条不在生成树上的边u -> v,不妨设fa为u.v的lca 则一fa到v的路径上的任意点x都可以由u达到,走的 ...
- 为什么 Node.js 这么火,而同样异步模式 Python 框架 Twisted 却十几年一直不温不火?
twisted是一个强大的异步网络框架,应用的面也非常广,但是没有这几年才出现的Node.js火,社区.文档也是很少可怜我觉得二者其实在本质上差不多,而且python使用起来还是比较容易一些的 匿名用 ...
- php 应用 cpu 100% 调试方法
找出进程占用cpu高的原因. 进程占用cpu高,一般是由于进程长时间占用cpu,又没有主动释放占用.如果想主动释放cpu,可以调用sleep.在写程序的时候,尤其要注意while 等循环的地方. 找出 ...
- 使用tomcat配置文件下载服务器,自定义下载列表
先上图,利用tomcat,这个下载界面没有代码,点击文件名即可下载 详细参考:http://tomcat.apache.org/tomcat-7.0-doc/default-servlet.html
- vbox内部linux :centos5.5与外部ping通(相互),而且域名访问
1 相互ping通:不能使用nat,nat只能单向通,虚拟机不能ping通主机,选择桥接: 如图: 2然后设置 ip:最好设置静态ip这样下次不用再改,这里我们只演示使用eth0网卡,=> vi ...
- 检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下:
检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下: 第 一步:首先将msvcr71.dll, SQLD ...
- S1:运算符
中括号和小括号的用法: 一般而言,对象中的属性的值是通过点(.)运算符来取值,但是考虑到这样一种情况,我们在遍历一个对象的时候,对其中的属性的键(key)是一无所知的,我们怎么通过点(.)来访问呢?这 ...