GCD实践——串行队列/并发队列与iOS多线程详解

来源:互联网 发布:城觅倒闭 知乎 编辑:程序博客网 时间:2024/06/15 14:36

       GCD(Grand Central Dispatch),是苹果提供的一个解决多线程开发的解决方案。GCD会自动管理线程的生命周期(创建线程,调度任务,销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时GCD使用block来进行任务的执行,用起来非常方便、灵活。本篇博客我们主要将GCD,其他的多线程实现方式还有NSThread、NSOperationQueue,我们将会在以后的博客中讲解。

       这里我们要提到一个概念:【任务】。就是操作,就是你要执行的一段代码,在GCD中就是一个Block,所以添加任务十分方便。

【同步执行】:只要是同步执行的任务,都会在当前线程执行,不会另开线程。所以说网络请求等耗时操作一般不使用同步,而是异步,否则会阻塞主线程,界面会卡住。

【异步执行】:只要是异步任务执行的任务,都会另开线程,在别的线程执行。

同步(sync)和异步(async)的主要区别在于会不会阻塞当前线程,直到Block中的任务执行完毕。     

如果是同步(sync)操作,它会阻塞当前线程并等待Block中的任务执行完毕,然后当前线程才会继续往下运行(因为同步操作没有开新线程,是在主线程中执行的,所以会阻塞)。

如果是异步(async)操作,当前线程会直接往下执行,他不会阻塞当前线程(因为异步操作是在另一个线程中执行的,所以不会阻塞主线程)。



队列:用于存放任务,一共有两种队列:串行队列和并行队列。

1.串行队列(private dispatch queue)一次只执行一个线程,按照添加到队列的顺序依次执行;

2.并行队列(global dispatch queue)一次可以执行多个线程,线程的执行没有先后顺序。根据同步或者异步有不同的执行方式。放到并行队列的任务,GCD也会FIFO的取出来,但不同的是,他取出来一个就会放到别的线程,然后再取出来一个又放到另一个线程。


3.Main dispatch queue:UI界面所在的线程队列是主线程。


下面我对上述几个案例进行代码示例:项目已经上传至github:   https://github.com/chenyufeng1991/GCD            。中的GCD1项目。

【串行队列示例】

(1)首先导入GCD封装后的代码,可以从我的项目中直接复制,总共9个文件:其实个人推荐使用iOS原生的GCD,请移步《iOS开发——GCD的使用与多线程开发浅析》这篇博客。


(2)ViewController中的实现如下:

#import "ViewController.h"#import "GCD.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {  [super viewDidLoad];  //执行串行队列;  [self serailQueue];  }//串行队列;- (void)serailQueue{  //创建出队列;  GCDQueue *queue = [[GCDQueue alloc] initSerial];    //执行队列中的线程;  [queue execute:^{        NSLog(@"1");      }];      [queue execute:^{        NSLog(@"2");      }];      [queue execute:^{        NSLog(@"3");      }];      [queue execute:^{        NSLog(@"4");      }];      [queue execute:^{        NSLog(@"5");      }];  }@end

(3)执行结果如下:


(4)结果分析

输出结果和我们的预期一样,是按照添加到队列的顺序执行的。


【并行队列示例】

(1)同样需要引入GCD源代码,在ViewController中的实现如下:

#import "ViewController.h"#import "GCD.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {  [super viewDidLoad];    //执行并发队列;  [self concurrent];   }//并发队列;- (void)concurrent{  //创建出队列;  GCDQueue *queue = [[GCDQueue alloc] initConcurrent];    //执行队列中的线程;  [queue execute:^{        NSLog(@"1");      }];      [queue execute:^{        NSLog(@"2");      }];      [queue execute:^{        NSLog(@"3");      }];      [queue execute:^{        NSLog(@"4");      }];      [queue execute:^{        NSLog(@"5");      }];  }@end

(2)结果输出:


(3)结果分析:

输出结果和我们预期的一样,执行的顺序是无序的。


【UI界面更新】

(1)使用GCD,我们可以来进行网络操作或者下载请求,然后更新UI。这一系列操作是串行操作,需要有一定的顺序。在这里我使用了同步请求。在ViewController中实现如下:

#import "ViewController.h"#import "GCD.h"@interface ViewController ()@property(strong,nonatomic) UIImage *image;@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)viewDidLoad {  [super viewDidLoad];  //globalqueue其实就是并行队列。  [GCDQueue executeInGlobalQueue:^{        //处理业务逻辑    NSString *url = @"http://imgsrc.baidu.com/forum/w%3D580/sign=2e824145d2c8a786be2a4a065708c9c7/5a8e72094b36acaf254077437fd98d1000e99c4a.jpg";    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];    NSData *picData = [NSURLConnection sendSynchronousRequest:request                                            returningResponse:nil                                                        error:nil];        NSLog(@"处理业务逻辑");        //获取图片;    self.image = [UIImage imageWithData:picData];        [GCDQueue executeInMainQueue:^{            NSLog(@"更新UI");            //更新UI      [self.imageView setImage:self.image];                }];          }];  }@end

(2)注意,我在storyboard中放了一个ImageView控件。运行效果如下:


github主页:https://github.com/chenyufeng1991  。欢迎大家访问!

2 0
原创粉丝点击