iOS并发编程之GCD使用介绍

GCD的全称Grand Central Dispatch,是iOS开发中最常用的并发编程方式之一,今天我带领大家详细的领略一下GCD编程的强大之处。

上一期,我们提到GCD是系统提供的一套C语言函数级别的并发编程方式,其核心思想就是将需要并发执行的任务封装到block里,通过把block分发到不同类型的队列里,对不同类型的队列,实现并发执行。从前面我们可以看出,GCD中三个关键点是:C语言的API、block和队列。block是Objective-c的一种编码语法,这里不做介绍了,感兴趣的同学可以查看官方文档。接下来我们一起进入GCD中C语言API和队列的世界。

首先,看一段GCD实现并发编程的代码:

// dispatch_get_global_queue是用于获取系统提供的并发队列,
// dispatch_async用于把封装好的block分发到指定的队列里,异步执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    // 待执行的任务代码
                });

上面代码中包含了GCD的三个关键点,

  1. dispatch_async函数,这是一个异步分发的函数,把待执行的任务分发到对应的queue中,然后此函数立即返回,无需等待任务执行完成。函数的第一个参数是队列,第二个参数是封装任务的block。
  2. dispatch_get_global_queue,这是一个获取系统提供的队列的方法,对于队列,之后在详细介绍。
  3. ^{// 待执行的任务代码},这是封装任务的block。

然后,我带领大家从里往外探索GCD中间的关键点:

1. 封装任务的block。这里是待执行的任务代码,以block的形式存在。
2. 队列(queue)。在GCD中,队列是决定任务执行方式的关键元素。GCD总共有3种形式的队列——顺序队列(serial queue)、并发队列(concurrency queue)和主队列(main queue)。

<<<<顺序队列:如其名,这种队列里的任务都是按照顺序执行的,严格按照FIFO,前一个任务执行完成之后,才会开始下一个任务。可以理解成一个顺序队列对应一个线程,队列里的任务都是按照先进先出的模式,在同一个线程中顺序执行。顺序队列的好处是,执行任务的线程不是主线程,不会阻塞程序主线程。同时同一顺序队列中的所有任务是按照顺序执行,不存在并发问题。但是不同顺序队列的任务是并发执行的,顺序队列和并发队列中的任务也是并发执行的。顺序队列的使用方式如下:

    static dispatch_queue_t serialQueue;
    if (!serialQueue) {

        serialQueue = dispatch_queue_create("Test Queue", DISPATCH_QUEUE_SERIAL);
    }
    dispatch_async(serialQueue, ^{

        // 待顺序执行任务代码
    });

<<<<并发队列:这种队列中的任务是并发执行的,虽然任务出队是按照FIFO,但是队列中的任务可能有多个线程同时执行,故任务执行完成的顺序是不定的。在此队列中的任务,不仅不会阻塞主线程,同时任务都是并发执行的,能够很好的提高程序效率,但是对于任务的共享资源,需要做同步。并发队列总共有两种,一种是系统提供的并发队列,通过dispatch_get_global_queue获取,另一种则是开发者自己创建的并发队列。下面是两种并发队列的使用方式:

    // 使用系统提供的并发队列,通过dispatch_get_global_queue函数获取,
    // 第一个参数为队列的优先级,第二个参数是给以后预留的参数,传0即可
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(concurrentQueue, ^{
        // 待顺序执行任务代码
    });
    // 开发者自己创建并发队列
    static dispatch_queue_t concurrencyQueue;
    if (!concurrencyQueue) {

        concurrencyQueue = dispatch_queue_create("Test Queue", DISPATCH_QUEUE_CONCURRENT);
    }
    dispatch_async(concurrencyQueue, ^{

        // 待并发执行任务代码
    });

<<<<主队列:主队列是对应于APP主线程的一个队列,所有主队列中的任务都是在主线程中执行的。此队列由系统提供,开发者不能创建。其本质是一种顺序队列,由于其中的任务都是在主线程执行,故是比较特殊的顺序队列。当开发者需要把任务放在主线程中执行,又不能确定当前线程是否是主线程是,可以把任务通过GCD分发到主队列,这样就能保证任务是在主线程中完成的。由于主队列所有的任务都是在主线程中执行,故不要把费时的任务分发到主队列,否则会阻塞主线程,降低体验。主队列的使用方式如下:

    // dispatch_get_main_queue是获取主队列的函数
    dispatch_async(dispatch_get_main_queue(), ^{

        // 需要在主线程中执行的任务代码
    });

3. 分发函数。 GCD中提供了很多用于并发开发的函数,包括分发函数、队列操作函数、任务依赖函数等等,比如之前提到的创建队列函数(dispatch_queue_create)、获取队列函数(dispatch_get_global_queue)等等。下面给大家介绍一下最常用的分发函数,其他功能的函数在以后会慢慢带领大家学习。GCD的分发函数主要分为两类——同步分发函数和异步分发函数。这两种分发函数的区别是函数是否等待分发的任务执行完成在返回。同步分发函数会等待分发的任务执行完成,函数才会返回。而异步分发则无需等待任务执行完成,函数会立即返回。

<<<<同步分发函数:同步分发函数主要由两个dispatch_sync和dispatch_sync_f,前者是我们之前介绍的,把任务封装成block,而后者是把任务封装成函数。dispatch_sync的第一个参数是队列,第二个参数是任务的block,通过同步分发,当前线程会被阻塞,等待分发任务执行完成,然后继续当前线程,即同步分发函数需要等待任务执行完成,才会返回。例子如下:

    // 开发者自己创建并发队列
    static dispatch_queue_t concurrencyQueue;
    if (!concurrencyQueue) {

        concurrencyQueue = dispatch_queue_create("Test Queue", DISPATCH_QUEUE_CONCURRENT);
    }
    NSLog(@"分发任务之前!");
    dispatch_sync(concurrencyQueue, ^{

        // 待并发执行任务代码

        NSLog(@"并发任务执行完成!");
    });
    NSLog(@"原线程继续运行!");

    /*
        上面代码的运行结果是(注意日志的先后顺序):
            分发任务之前!
            并发任务执行完成!
            原线程继续运行!
    */

<<<<异步分发函数:与同步分发函数类似,异步分发函数也有两个dispatch_async和dispatch_async_f。dispatch_async的第一个参数是队列,第二个参数是任务的block,通过异步分发,当前线程不会被阻塞,分发完就会继续运行当前线程,即异步分发函数无需等待任务执行完成,就会立即返回。例子如下:

    // 开发者自己创建并发队列
    static dispatch_queue_t concurrencyQueue;
    if (!concurrencyQueue) {

        concurrencyQueue = dispatch_queue_create("Test Queue", DISPATCH_QUEUE_CONCURRENT);
    }
    NSLog(@"分发任务之前!");
    dispatch_async(concurrencyQueue, ^{

        // 待并发执行任务代码
        NSLog(@"并发任务执行完成!");
    });
    NSLog(@"原线程继续运行!");

    /*
        上面代码的运行结果是(注意日志的先后顺序):
            分发任务之前!
            原线程继续运行!
            并发任务执行完成!
    */

总结,GCD是一组C语言级别的并发编程API,主要是通过函数API、队列和block来完成。队列分为三种:顺序队列、并发队列和主队列。函数API包含很多不同功能的函数,最主要的就是分发函数和队列操作函数。block并发执行的方式是由队列的类型来决定的,而分发函数决定了当前线程是否需要等待block运行完成。由于GCD把任务封装到block,嵌入到执行的地方,故让开发者很容易理解到并发任务的功能,同时GCD的语法非常简洁易用,平时开发过程中,建议开发者多采用这种方式实现并发编程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值