首页 > 代码库 > IOS多线程开发之GCD

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都不一样,而且这些都同时执行,说明在不同的线程同时执行,而同步的线程信息和主线程信息相同。

IOS多线程开发之GCD