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. 刚刚回归的开始菜单 Windows 10全面体验

    北京时间2014年10月1日凌晨,微软就在旧金山召开新品公布会,对外展示了自己新一代操作系统Windows 10,覆盖了包含手机.平板.台式机以及Xbox One在内的全部平台.尽管微软此次公布的不过 ...

  2. lua for通过循环table一些差异

    有两个著名的是:ipairs和pairs,双方都认为,我们都非常熟悉的.其中ipairs刮(idx=1)从明年序遍历,经验nil那退出循环:和pairs遍历,仅仅要里面有值都能够遍历的到. 那假如我须 ...

  3. sql server 辅助工具

    sql Prompt 智能感知, 也是需要注册机. 效果如图: 这里最好改下:

  4. (工具)source insight高速增加时间代码

    这篇文章是程序代码更改由其他用户. 不是原厂原装,例如下列总结,使用作为个人笔记. (1)打开projectbase.打开文件Utils.em,插入下面代码: //插入时间 macro MonthTo ...

  5. MVC4 学习笔记01

    1 . ASP.NET MVC 中 ActionResult 和 ViewResult 在使用上的区别是什么?要注意什么吗? ActionResult 是一个抽象(abstract)类,ViewRes ...

  6. LayOutControl

    DevExpress DXperience 12.2 在 Navigation & Layout 中 有个 LayOutControl 它适用于做布局,我们普通控件 长宽 只能给固定的值,这个 ...

  7. 对JSON数组对象排序-有键相同的元素,分组数量不一致,可采用如下的JS进行循环表格输出

    var now=eval(data.data); // now.sort(sortBy('bigIdOrder', true, parseInt)); var tab=""; va ...

  8. loadrunner必用函数web_reg_save_param获取多个符合边界值条件的使用方法

    在做loadrunner性能脚本开发时,常常碰见一个需求:符合web_reg_save_param函数中定义的左右边界值的值有多个,而我们的常规写法默认返回的是符合条件的第一个,而有时我们却需要使用后 ...

  9. changePage() 页面跳转

    jQuery.mobile.changePage( to [, options ] ) 从一个页面跳转到另一个页面,使用$.mobile对象的changePage方法来实现.但要使用此方式的时候,要以 ...

  10. Android摘要ImageView的scaleType属性

    Android在ImageView的scaleType有8一个选项 1 matrix不正确图像放大,原来自view在左上角绘制图片(片不变形): 2 fitXY将图片所有绘制到view中,可是图片会变 ...