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释放。比如下面两段代码分别创建串行队列和并行队列:

      1. dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);
      2. dispatch_async(serialQ, ^{
      3. // Code here
      4. });
      5. dispatch_release(serialQ);
      6. dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
      7. dispatch_async(concurrentQ, ^{
      8. // Code here
      9. });
      10. dispatch_release(concurrentQ);

      而系统默认就有一个串行队列main_queue和并行队列global_queue:

      1. dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      2. dispatch_queue_t mainQ = dispatch_get_main_queue();

      通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:

      1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      2. // long-running task
      3. dispatch_async(dispatch_get_main_queue(), ^{
      4. // update UI
      5. });
      6. });

      上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。由于block是定义在栈上的,所以需要将其复制到堆上,见这里

      与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:

      1. dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );
      2. dispatch_sync( exampleQueue,^{
      3. dispatch_sync( exampleQueue,^{
      4. printf("I am now deadlocked...\n");
      5. });});
      6. dispatch_release( exampleQueue );

      如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,StackOverFlow是这样讨论的:

      Can anyone explain with really clear use cases what the purpose of dispatch_sync in GCD 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 queue q. 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中:

      1. -(void)viewDidAppear:(BOOL)animated{
      2. dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      3. dispatch_async(concurrentQueue, ^{
      4. __block UIImage *image = nil;
      5. dispatch_sync(concurrentQueue, ^{
      6. /* 下载图片 */
      7. NSString *urlAsString = @"http://images.apple.com/mac/home/images/promo_lead_macbook_air.jpg";
      8. NSURL *url = [NSURL URLWithString:urlAsString];
      9. NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
      10. NSError *downloadError = nil;
      11. NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&downloadError];
      12. if (downloadError == nil && imageData != nil){
      13. image = [UIImage imageWithData:imageData];
      14. } else if(downloadError!=nil){
      15. NSLog(@"Error happened = %@", downloadError);
      16. }else {
      17. NSLog(@"No data could get downloaded from the URL.");
      18. }
      19. });
      20. //在主队列中把图片展示给用户
      21. dispatch_sync(dispatch_get_main_queue(), ^{
      22. if (image != nil){
      23. /* 创建一个UIImageView */
      24. UIImageView *imageView = [[UIImageView alloc]
      25. initWithFrame:self.view.bounds];
      26. /* 设置图片*/
      27. [imageView setImage:image];
      28. /* 设置图片比例*/
      29. [imageView setContentMode:UIViewContentModeScaleAspectFit];
      30. /* 添加视图 */
      31. [self.view addSubview:imageView];
      32. } else {
      33. NSLog(@"Image isn't downloaded. Nothing to display.");
      34. } });
      35. });
      36. }

      运行结果:

IOS学习之路八(GCD与多线程)的更多相关文章

  1. IOS开发---菜鸟学习之路--(二十二)-近期感想以及我的IOS学习之路

    在不知不觉当中已经写了21篇内容 其实一开始是没有想些什么东西的 只是买了Air后 感觉用着挺舒服的,每天可以躺在床上,就一台笔记本,不用网线,不用电源,不用鼠标,不用键盘,干干脆脆的就一台笔记本. ...

  2. 浅谈iOS学习之路(转)

    转眼学习iOS已经快两年的时间了,这个路上有挫折也有喜悦,一步步走过来发现这个过程是我这一辈子的财富,我以前的老大总是对我说,年轻就是最大的资本(本人91年),现在才算是慢慢的体会到,反观自己走过的这 ...

  3. 浅谈iOS学习之路

    转眼学习iOS已经快两年的时间了,这个路上有挫折也有喜悦,一步步走过来发现这个过程是我这一辈子的财富,我以前的老大总是对我说,年轻就是最大的资本(本人91年),现在才算是慢慢的体会到,反观自己走过的这 ...

  4. IOS7学习之路八(iOS 禁止屏幕旋转的方法)

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { retu ...

  5. IOS学习之路十八(通过 NSURLConnection 发送 HTTP 各种请求)

    你想通过 Http 协议向服务器发送一个 Get 的包装请求,并在这个请求中添加了一些请 求参数. 向远程服务器发送一个 GET 请求,然后解析返回的数据.通常一个 GET 请求是添加了 一些参数的, ...

  6. IOS学习之路--OC的基础知识

    1.项目经验 2.基础问题 3.指南认识 4.解决思路 ios开发三大块: 1.Oc基础 2.CocoaTouch框架 3.Xcode使用 -------------------- CocoaTouc ...

  7. 纪录我的iOS学习之路

    学习资料的网址 田伟宇(Casa Taloyum)有几篇介绍iOS架构的文章,一级棒!原博客链接. iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方 ...

  8. 我的IOS学习之路(三):手势识别器

    在iOS的学习中,对于手势的处理是极为重要的,如对于图片,我们经常需要进行旋转,缩放以及移动等.这里做一下总结,详见代码. - (void)viewDidLoad { [super viewDidLo ...

  9. Java学习笔记(八)——java多线程

    [前面的话] 实际项目在用spring框架结合dubbo框架做一个系统,虽然也负责了一块内容,但是自己的能力还是不足,所以还需要好好学习一下基础知识,然后做一些笔记.希望做完了这个项目可以写一些dub ...

随机推荐

  1. java_ java多线程返回函数结果

    两种方式:一种继承Thread类实现:一种通过实现Callable接口. 第一种方法: 因为实现Thread类的run方法自身是没有返回值的,所以不能直接获得线程的执行结果,但是可以通过在run方法里 ...

  2. HDU 2070 Fibbonacci Number

    Fibbonacci Number Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  3. crm创建和编辑全局选项集

    一个选项集就是可包含在一个实体中的某种类型的字段.它定义一组选项.当一个选项集显示在窗口中时,将使用下拉列表控件.当在 Advanced Find 中显示时,则使用选择列表控件.有时,开发者将选项集称 ...

  4. PHP的MySQL扩张:MySQL数据库概述

    资源:http://www.ido321.com/1023.html 一.SQL:结构化查询语言 SQL(Structured Query Language)是高级的非过程化变成语言.专门用于查询和改 ...

  5. 图数据库 Titan 高速入门

    尤其在互联网世界,图计算越来越受到人们的关注,而图计算相关的软件也越来越丰富.本文将高速展示 Titan这个open source 的图数据库. 注:本文的操作主要基于Titan 官方的两篇文档: - ...

  6. CentOS 使用yum命令安装Java SDK(openjdk)

    CentOS 6.X 和 5.X 自带有OpenJDK runtime environment  (openjdk).它是一个在linux上实现开源的java 平台.CentOS  yum 命令 安装 ...

  7. 开源Dubbox

    当当网开源Dubbox https://github.com/dangdangdotcom/dubbox https://github.com/alibaba/dubbo http://www.inf ...

  8. Js创建对象的做法

    1.对象工具包 <html> <head> <meta http-equiv="Content-Type" content="text/ht ...

  9. 使用JavaCompiler编译java源文件

    从1.6版本的JDK开始,JDK提供了标准的包可以方便的调用JVM的编译器,可以方便的使用JVM的编译器来编译java源文件.JDK提供的调用接口是JavaCompiler类,该类在JDK的tools ...

  10. 添加MySql Metat Database 信息

    有时候我们想看看 一个数据库上面 某种元素(比如表名)的所有信息,在Mysql上 我们可以通过引入information_schema 的方式,就可以非常方便的查看到. 添加步骤 Edit->P ...