GCD笔记

来源:互联网 发布:js cookie 编辑:程序博客网 时间:2024/06/05 16:55

一、什么是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 任务开始执行\r\n");      //延长taskFirst的运行时间     for (UInt32 i = 0; i < loopCountFirst; i++) {               }     NSLog(@"taskFirst 任务结束\r\n");};        void (^taskSecond)(void) = ^{      NSLog(@"taskSecond任务开始执行\r\n");       for (UInt32 i = 0; i < loopCount; i ++) {                    }      NSLog(@"taskSecond 任务结束\r\n"); };dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_async(concurrentQueue, taskFirst);NSLog(@"taskfirst 已经加入队列\r\n");dispatch_async(concurrentQueue, taskSecond);NSLog(@"tasksecond 已经加入队列\r\n");
复制代码

 

另外,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使用的文章,此文中有些内容本人觉得无法比唐巧写得好变摘录过来,敬请谅解!

0 0
原创粉丝点击