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. }

      运行结果:

最新文章

  1. 如何利用Pre.im分发iOS测试包
  2. 【Android开发坑系列】如何让Service尽可能存活
  3. Ecshop 最小起订量如何设置
  4. 【推荐】oc解析HTML数据的类库(爬取网页数据)
  5. seq 显示00 01的格式
  6. Sample Join Analysis
  7. zabbix 分布式监控(proxy)源码安装
  8. URAL 1671 Anansi's Cobweb (并查集)
  9. SQL查询中的in与join效率比较
  10. .Net中C#的DllImport的用法
  11. 【JAVA错误笔记】 - c3p0问题java.lang.NoClassDefFoundError:com.mchange.v2.ser.Indirector
  12. 一个cocos2d程序的完整人生(从环境到代码全过程)
  13. 在win7下装ubuntu(硬盘版安装)及遇到的问题
  14. Linux环境下使用eclipse开发C++动态链接库程序
  15. Linux系统部署规范v1.0
  16. 持续集成 windows下jenkins常见问题填坑
  17. 微信web开发工具
  18. Windows下Nginx的安装与使用(一):配置端口转发
  19. pseudo-class与pseudo-element的不同点与相同点
  20. 小程序如何获取code

热门文章

  1. 只有有lua编译能力不足200K代码吧?NO! Python 有可能。
  2. 还是畅通project(杭州电1233)
  3. .net mvc ajax list post
  4. BZOJ 3282 Tree Link-Cut-Tree(LCT)
  5. MVC4 学习笔记01
  6. 简单DP-艰难取舍
  7. Java实现缓存(类似于Redis)
  8. C语言库函数大全及应用实例十三
  9. VS2015 Apache Cordova
  10. leetcode 第41题 Trapping Rain Water