• GCD笔记


    一、什么是GCD?

      Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。

    二、什么时候使用多线程

      我个人理解,在实际开发中我们常常把那些比较耗时且与UI无关的操作放到非主线程中去执行,避免这些耗时操作阻塞主线程导致界面操作起来很卡。比如:加载网络数据、本地存储、读取、更新大量数据这些情况都应该使用多线程。

    三、没有GCD之前

      在GCD没有出现之前,在处理多线程的时候你可能用过(NSThread),(NSOperationQueue和NSInvocationOperation结合),或者是使用iOS提供的以下几个便捷方法:

    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

    - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg NS_AVAILABLE(10_5, 2_0);

    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

    以上几种方法都有一个共同的缺点就是代码比较分散,降低程序的可读性

    例如下面这段代码:(版权为唐巧)

    static NSOperationQueue * queue;
    
    - (IBAction)someClick:(id)sender {
        self.indicator.hidden = NO;
        [self.indicator startAnimating];
        queue = [[NSOperationQueue alloc] init];
        NSInvocationOperation * op = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil] autorelease];
        [queue addOperation:op];
    }
    
    - (void)download {
        NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"];
        NSError * error;
        NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
        if (data != nil) {
            [self performSelectorOnMainThread:@selector(download_completed:) withObject:data waitUntilDone:NO];
        } else {
            NSLog(@"error when download:%@", error);
            [queue release];
        }
    }
    
    - (void) download_completed:(NSString *) data {
        NSLog(@"call back");
        [self.indicator stopAnimating];
        self.indicator.hidden = YES;
        self.content.text = data;
        [queue release];
    }

    四、有了GCD以后

    因为GCD采用了block的语法,因此我们可以把操作都放到block的代码块当中去执行(强烈建议在阅读本文之前先了解一些block的相关知识),还有一个优点就是GCD的API全部是c语言且是苹果强烈推荐使用,因此个人觉得在处理效率上应该相对其他几种方式要高一些。

    如果使用GCD,以上3个方法都可以放到一起,如下所示:

    // 原代码块一
    self.indicator.hidden = NO;
    [self.indicator startAnimating];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 原代码块二
        NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"];
        NSError * error;
        NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
        if (data != nil) {
            // 原代码块三
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.indicator stopAnimating];
                self.indicator.hidden = YES;
                self.content.text = data;
            });
        } else {
            NSLog(@"error when download:%@", error);
        }
    });

    五、系统提供的dispatch方法

    乍一看,gcd的语法貌似很复杂,其实很简单,苹果为了方便我们使用GCD,提供了包括后台执行、主线程执行、延后执行等一系列方法具体如下:

     //  后台执行:
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
          // something
     });
     // 主线程执行:
     dispatch_async(dispatch_get_main_queue(), ^{
          // something
     });
     // 一次性执行:
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         // code to be executed once
     });
     // 延迟2秒执行:
     double delayInSeconds = 2.0;
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
         // code to be executed on the main queue after delay
     });

    dispatch_queue_t 也可以自己定义,如要要自定义queue,可以用dispatch_queue_create方法,示例如下:

    dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
    dispatch_async(urls_queue, ^{
         // your code
    });
    dispatch_release(urls_queue);

    两个线程并行

    并行队列是不允许自己创建的,系统中存在三个不同优先级的并行队列。并行队列依旧按照任务添加的顺序启动任务,但是,后一个任务无须等待前一个任务执行完毕,而是启动第一个任务后,立即启动下一个任务。至于同一时刻允许同时运行多少个任务有系统决定。任务各自运行在并行队列为他们提供的独立线程上,并行队列中同时运行多少个任务,就必须维护多少个线程。

     UInt32 loopCount = 1000;
    UInt32 loopCountFirst = 10000000;
    void (^taskFirst)(void) = ^{
         NSLog(@"taskFirst 任务开始执行
    "); 
         //延长taskFirst的运行时间
         for (UInt32 i = 0; i < loopCountFirst; i++) {          
         }
         NSLog(@"taskFirst 任务结束
    ");
    };    
        void (^taskSecond)(void) = ^{
          NSLog(@"taskSecond任务开始执行
    ");
           for (UInt32 i = 0; i < loopCount; i ++) {             
           }
          NSLog(@"taskSecond 任务结束
    ");
     };
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(concurrentQueue, taskFirst);
    NSLog(@"taskfirst 已经加入队列
    ");
    dispatch_async(concurrentQueue, taskSecond);
    NSLog(@"tasksecond 已经加入队列
    ");

    另外,GCD还有一些高级用法,例如让后台2个线程并行执行,然后等2个线程都结束后,再汇总执行结果。这个可以用dispatch_group, dispatch_group_async 和 dispatch_group_notify来实现,示例如下:

     dispatch_group_t group = dispatch_group_create();
     dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
          // 并行执行的线程一
     });
     dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
          // 并行执行的线程二
     });
     dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
          // 汇总结果
     });

    六、总结

    GCD极大地方便了iOS开发者使用多线程来完成数据与UI的交互,且充分利用了当今处理器的多核功能,既提高了效率又方便了使用。

    非常感谢唐巧的一篇gcd使用的文章,此文中有些内容本人觉得无法比唐巧写得好变摘录过来,敬请谅解!

  • 相关阅读:
    day12_字符连接单引号转意字符
    day12_存储过程说明
    day12_PLSQL编程--存储过程---统一发布动态属性管理
    linux关闭celinux服务
    day11__表管理
    day11_分区表------子分区的母模板(11g)
    day11_分区表------子分区的母模板(10g)
    day11_分区表——分区表常用维护
    smartforms 中的currquan单位处理
    当SVN服务器端IP地址发生变化时,客户端重新定位
  • 原文地址:https://www.cnblogs.com/zzltjnh/p/zzl_gcd.html
Copyright © 2020-2023  润新知