IOS学习之路八(GCD与多线程)
GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制。它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不保证一定先执行结束)。
通过与线程池的配合,dispatch queue分为下面两种:
- Serial Dispatch Queue -- 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
- Concurrent Dispatch Queue -- 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。
1. Basic Management
我们可以通过dispatch_queue_cretae来创建队列,然后用dispatch_release释放。比如下面两段代码分别创建串行队列和并行队列:
- dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);
- dispatch_async(serialQ, ^{
- // Code here
- });
- dispatch_release(serialQ);
- dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
- dispatch_async(concurrentQ, ^{
- // Code here
- });
- dispatch_release(concurrentQ);
而系统默认就有一个串行队列main_queue和并行队列global_queue:
- dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_queue_t mainQ = dispatch_get_main_queue();
通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- // long-running task
- dispatch_async(dispatch_get_main_queue(), ^{
- // update UI
- });
- });
上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。由于block是定义在栈上的,所以需要将其复制到堆上,见这里。
与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:
- dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );
- dispatch_sync( exampleQueue,^{
- dispatch_sync( exampleQueue,^{
- printf("I am now deadlocked...\n");
- });});
- dispatch_release( exampleQueue );
如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,StackOverFlow是这样讨论的:
Can anyone explain with really clear use cases what the purpose of
dispatch_sync
inGCD
is for? I can't understand where and why I would have to use this.高手回答:
You use it when you want to execute a block and wait for the results.
One example of this is the pattern where you're using a dispatch queue instead of locks for synchronization. For example, assume you have a shared NSMutableArray
a
, with access mediated by dispatch queueq
. A background thread might be appending to the array (async), while your foreground thread is pulling the first item off (synchronously):NSMutableArray*a =[[NSMutableArray alloc] init];// All access to `a` is via this dispatch queue!dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", NULL); dispatch_async(q,^{[a addObject:something];});// append to array, non-blocking __block Something*first = nil;// "__block" to make results from block available
dispatch_sync(q,^{// note that these 3 statements...if([a count]>0){// ...are all executed together...
first =[a objectAtIndex:0];// ...as part of a single block...[a removeObjectAtIndex:0];// ...to ensure consistent results}});下面附上一个Demo :(后台队列下载图片,当下载完后,调用主线程在前台显示)
在Concoller中:
- -(void)viewDidAppear:(BOOL)animated{
- dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_async(concurrentQueue, ^{
- __block UIImage *image = nil;
- dispatch_sync(concurrentQueue, ^{
- /* 下载图片 */
- NSString *urlAsString = @"http://images.apple.com/mac/home/images/promo_lead_macbook_air.jpg";
- NSURL *url = [NSURL URLWithString:urlAsString];
- NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
- NSError *downloadError = nil;
- NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&downloadError];
- if (downloadError == nil && imageData != nil){
- image = [UIImage imageWithData:imageData];
- } else if(downloadError!=nil){
- NSLog(@"Error happened = %@", downloadError);
- }else {
- NSLog(@"No data could get downloaded from the URL.");
- }
- });
- //在主队列中把图片展示给用户
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (image != nil){
- /* 创建一个UIImageView */
- UIImageView *imageView = [[UIImageView alloc]
- initWithFrame:self.view.bounds];
- /* 设置图片*/
- [imageView setImage:image];
- /* 设置图片比例*/
- [imageView setContentMode:UIViewContentModeScaleAspectFit];
- /* 添加视图 */
- [self.view addSubview:imageView];
- } else {
- NSLog(@"Image isn't downloaded. Nothing to display.");
- } });
- });
- }
运行结果:
IOS学习之路八(GCD与多线程)的更多相关文章
- IOS开发---菜鸟学习之路--(二十二)-近期感想以及我的IOS学习之路
在不知不觉当中已经写了21篇内容 其实一开始是没有想些什么东西的 只是买了Air后 感觉用着挺舒服的,每天可以躺在床上,就一台笔记本,不用网线,不用电源,不用鼠标,不用键盘,干干脆脆的就一台笔记本. ...
- 浅谈iOS学习之路(转)
转眼学习iOS已经快两年的时间了,这个路上有挫折也有喜悦,一步步走过来发现这个过程是我这一辈子的财富,我以前的老大总是对我说,年轻就是最大的资本(本人91年),现在才算是慢慢的体会到,反观自己走过的这 ...
- 浅谈iOS学习之路
转眼学习iOS已经快两年的时间了,这个路上有挫折也有喜悦,一步步走过来发现这个过程是我这一辈子的财富,我以前的老大总是对我说,年轻就是最大的资本(本人91年),现在才算是慢慢的体会到,反观自己走过的这 ...
- IOS7学习之路八(iOS 禁止屏幕旋转的方法)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { retu ...
- IOS学习之路十八(通过 NSURLConnection 发送 HTTP 各种请求)
你想通过 Http 协议向服务器发送一个 Get 的包装请求,并在这个请求中添加了一些请 求参数. 向远程服务器发送一个 GET 请求,然后解析返回的数据.通常一个 GET 请求是添加了 一些参数的, ...
- IOS学习之路--OC的基础知识
1.项目经验 2.基础问题 3.指南认识 4.解决思路 ios开发三大块: 1.Oc基础 2.CocoaTouch框架 3.Xcode使用 -------------------- CocoaTouc ...
- 纪录我的iOS学习之路
学习资料的网址 田伟宇(Casa Taloyum)有几篇介绍iOS架构的文章,一级棒!原博客链接. iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方 ...
- 我的IOS学习之路(三):手势识别器
在iOS的学习中,对于手势的处理是极为重要的,如对于图片,我们经常需要进行旋转,缩放以及移动等.这里做一下总结,详见代码. - (void)viewDidLoad { [super viewDidLo ...
- Java学习笔记(八)——java多线程
[前面的话] 实际项目在用spring框架结合dubbo框架做一个系统,虽然也负责了一块内容,但是自己的能力还是不足,所以还需要好好学习一下基础知识,然后做一些笔记.希望做完了这个项目可以写一些dub ...
随机推荐
- java_ java多线程返回函数结果
两种方式:一种继承Thread类实现:一种通过实现Callable接口. 第一种方法: 因为实现Thread类的run方法自身是没有返回值的,所以不能直接获得线程的执行结果,但是可以通过在run方法里 ...
- HDU 2070 Fibbonacci Number
Fibbonacci Number Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- crm创建和编辑全局选项集
一个选项集就是可包含在一个实体中的某种类型的字段.它定义一组选项.当一个选项集显示在窗口中时,将使用下拉列表控件.当在 Advanced Find 中显示时,则使用选择列表控件.有时,开发者将选项集称 ...
- PHP的MySQL扩张:MySQL数据库概述
资源:http://www.ido321.com/1023.html 一.SQL:结构化查询语言 SQL(Structured Query Language)是高级的非过程化变成语言.专门用于查询和改 ...
- 图数据库 Titan 高速入门
尤其在互联网世界,图计算越来越受到人们的关注,而图计算相关的软件也越来越丰富.本文将高速展示 Titan这个open source 的图数据库. 注:本文的操作主要基于Titan 官方的两篇文档: - ...
- CentOS 使用yum命令安装Java SDK(openjdk)
CentOS 6.X 和 5.X 自带有OpenJDK runtime environment (openjdk).它是一个在linux上实现开源的java 平台.CentOS yum 命令 安装 ...
- 开源Dubbox
当当网开源Dubbox https://github.com/dangdangdotcom/dubbox https://github.com/alibaba/dubbo http://www.inf ...
- Js创建对象的做法
1.对象工具包 <html> <head> <meta http-equiv="Content-Type" content="text/ht ...
- 使用JavaCompiler编译java源文件
从1.6版本的JDK开始,JDK提供了标准的包可以方便的调用JVM的编译器,可以方便的使用JVM的编译器来编译java源文件.JDK提供的调用接口是JavaCompiler类,该类在JDK的tools ...
- 添加MySql Metat Database 信息
有时候我们想看看 一个数据库上面 某种元素(比如表名)的所有信息,在Mysql上 我们可以通过引入information_schema 的方式,就可以非常方便的查看到. 添加步骤 Edit->P ...