IOS多线程开发之GCD
概要
GCD的全称是Grand Central Dispatch(译为中心调度队列?),可以理解为线程管理队列,是苹果公司为多核的并行运算提出的解决方案,能够根据系统环境自适应线程管理,基本属于全自动的线程管理。
在GCD里面,任务需要放到队列里面执行,队列根据自身属性分发任务执行,不过原则总是FIFO。队列分为串行和并行队列,串行队列是队列里面只有一个线程,所以队列里面只有一个任务在执行,而并行则会根据系统环境,自动调节线程数,可支持同时多个任务执行。
GCD提供了创建以及获取队列的方法,包括获取全局并发队列、串行主线程队列以及创建自己的串行队列(为什么没有创建并发的?个人理解是需要创建并发的和直接使用全局并发的效果一样)。串行队列因为同时只能执行一个任务的特点,所以可以满足某些需要按顺序执行任务的工作,用以充当锁、保护共享资源和数据。
串行队列
- 主线程队列
获取主线程队列,住主队列是GCD自带的一种串行队列,该主队列的任务会在主线程上执行。// 获取串行的主线程队列 dispatch_queue_t queue = dispatch_get_main_queue(); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async-%@"); }); // 同步执行任务 dispatch_sync(queue, ^{ NSLog(@"sync-%@"); });
- 自定义队列
// 创建队列,指定名称,属性设为默认即可 dispatch_queue_t queue = dispatch_queue_create("my_serial_queue", NULL); // 添加任务到队列 // 如果不是ARC的话,释放该队列 dispatch_release(queue);
并发队列
GCD提供的全局并发队列,供整个应用使用,不需要自己再去创建
GCD提供的全局并发队列,供整个应用使用,不需要自己再去创建 // 获取全局并发队列,可以选择优先级 // #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 同步执行block任务 dispatch_async(queue, ^{ NSLog(@"sync-%@"); }); // 异步执行block任务 dispatch_async(queue, ^{ NSLog(@"async-%@"); }); // 异步执行方法任务 dispatch_async_f(queue, queue_f);
主要函数列表
// 同步执行任务block dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); // 以异步的方式执行任务block dispatch_async(dispatch_queue_t queue, dispatch_block_t block); // 异步执行程序定义的方法 void dispatch_async_f ( dispatch_queue_t queue, void *context, dispatch_function_t work ); // 创建串行线程队列 dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); // 手动释放队列 void dispatch_release ( dispatch_object_t object ); // 获取串行主线程队列 dispatch_queue_t dispatch_get_main_queue ( void ); // 获取全局并发队列 dispatch_queue_t dispatch_get_global_queue ( long identifier, unsigned long flags ); // 获取当前代码的调度队列 dispatch_queue_t dispatch_get_current_queue ( void ); // 延迟异步执行block,对应的有函数dispatch_after_f void dispatch_after ( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block ); // 创建一个队列组 dispatch_group_t dispatch_group_create ( void );
代码示例
- 自定义串行队列
- (void)viewDidLoad { [super viewDidLoad]; // 主线程 NSLog(@"main-%@",[NSThread currentThread]); // 创建串行线程队列 dispatch_queue_t queue = dispatch_queue_create("my_serial", 0); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async1-%@", [NSThread currentThread]); }); // 同步执行任务 dispatch_sync(queue, ^{ NSLog(@"sync-%@", [NSThread currentThread]); }); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async2-%@", [NSThread currentThread]); }); }
输出结果
2015-01-01 15:00:35.213 GCDDemo[10763:14132221] main-<NSThread: 0x7fe192e158c0>{number = 1, name = main} 2015-01-01 15:00:35.214 GCDDemo[10763:14132356] async1-<NSThread: 0x7fe192d0b5d0>{number = 2, name = (null)} 2015-01-01 15:00:35.214 GCDDemo[10763:14132221] sync-<NSThread: 0x7fe192e158c0>{number = 1, name = main} 2015-01-01 15:00:35.214 GCDDemo[10763:14132356] async2-<NSThread: 0x7fe192d0b5d0>{number = 2, name = (null)}
因为是串行任务队列,所以队列只有一个线程,因此两个异步任务获取的线程信息一样其number都是1,而同步任务因为在主线程执行,所以获取的线程信息和主线程信息一样。此外,因为sync在async2之前,所以asyn要等到syn执行完毕。
- 主线程队列
- (void)viewDidLoad { [super viewDidLoad]; // 主线程 NSLog(@"main-%@",[NSThread currentThread]); // 创建串行线程队列,因为主线程队列需要在其他线程使用 dispatch_queue_t queue = dispatch_queue_create("my_serial", 0); // 异步执行任务 dispatch_async(queue, ^{ // 获取主线程队列 dispatch_queue_t queue = dispatch_get_main_queue(); // 同步执行任务 dispatch_sync(queue, ^{ NSLog(@"sync-%@", [NSThread currentThread]); }); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async-%@", [NSThread currentThread]); }); }); }
输出结果
2015-01-01 15:29:35.856 GCDDemo[10800:14143728] main-<NSThread: 0x7ff7d9f0e920>{number = 1, name = main} 2015-01-01 15:29:35.898 GCDDemo[10800:14143728] sync-<NSThread: 0x7ff7d9f0e920>{number = 1, name = main} 2015-01-01 15:29:35.900 GCDDemo[10800:14143728] async-<NSThread: 0x7ff7d9f0e920>{number = 1, name = main}
从直接结果可以看到获取的线程信息都一样,都是主线程信息,因为这些代码都是在主线程里面执行的。
- 全局队列
- (void)viewDidLoad { [super viewDidLoad]; // 主线程 NSLog(@"main-%@",[NSThread currentThread]); // 创建串行线程队列,因为主线程队列需要在其他线程使用 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async1-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"async1-finished, %@", [NSThread currentThread]); }); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async2-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"async2-finished, %@", [NSThread currentThread]); }); // 异步执行任务 dispatch_async(queue, ^{ NSLog(@"async3-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"async3-finished, %@", [NSThread currentThread]); }); // 异步执行任务 dispatch_sync(queue, ^{ NSLog(@"sync-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"sync-finished, %@", [NSThread currentThread]); }); }
输出结果
2015-01-01 15:41:11.802 GCDDemo[10851:14149580] main-<NSThread: 0x7f9cda427820>{number = 1, name = main} 2015-01-01 15:41:11.803 GCDDemo[10851:14149580] sync-started, <NSThread: 0x7f9cda427820>{number = 1, name = main} 2015-01-01 15:41:11.803 GCDDemo[10851:14149677] async3-started, <NSThread: 0x7f9cda624920>{number = 3, name = (null)} 2015-01-01 15:41:11.803 GCDDemo[10851:14149679] async2-started, <NSThread: 0x7f9cda4300c0>{number = 2, name = (null)} 2015-01-01 15:41:11.804 GCDDemo[10851:14149680] async1-started, <NSThread: 0x7f9cda608e80>{number = 4, name = (null)} 2015-01-01 15:41:12.809 GCDDemo[10851:14149680] async1-finished, <NSThread: 0x7f9cda608e80>{number = 4, name = (null)} 2015-01-01 15:41:13.808 GCDDemo[10851:14149679] async2-finished, <NSThread: 0x7f9cda4300c0>{number = 2, name = (null)} 2015-01-01 15:41:14.805 GCDDemo[10851:14149580] sync-finished, <NSThread: 0x7f9cda427820>{number = 1, name = main}
从执行结果可以三个异步部分的代码的nunber都不一样,而且这些都同时执行,说明在不同的线程同时执行,而同步的线程信息和主线程信息相同。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。