GCD的使用

作者: 少少白 | 来源:发表于2016-04-03 17:06 被阅读129次

多线程中GCD(Grand Central Dispatch)是我们比较常用,今天对于其的常见用法做以总结.

  • Dispatch Queue的种类一共有两种:

    1. Serial Dispatch Queue
    2. Concurrent Dispatch Queue

即串行和并行队列.当为串行队列时,加入到队列的任务需要等待上一个执行完才进行下一个,而并行队列时无需等待即可紧接着执行下一个任务.
创建一个串行队列:

    dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("io.github.junne.serialDispatchQueue", NULL);
    dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("io.github.junne.serialDispatchQueue", DISPATCH_QUEUE_SERIAL);

这里创建队列的第二个参数,NULL等同于DISPATCH_QUEUE_SERIAL.
创建一个并行队列:

    dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("io.github.junne.concurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
  • 系统提供的队列
    1. Main Dispatch Queue(Serial Dispatch Queue)
    2. Global Dispatch Queue(Concurrent Dispatch Queue)
      其中追加到Main Dispatch Queue的处理在主线程的Runloop执行,一般用于UI更新等必须在主线程进行的操作.而Global Dispatch Queue相当于系统为我们用dispatch_queue_create生成的一个Concurrent Dispatch Queue,我们可以将一些多线程操作追加到这个队列中.
      Global Dispatch Queue有四个执行优先级. High Priority、Default Priority、Low Priority和Background Priority,创建方法为:
    dispatch_queue_t globalDispatchQueueHigh        = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    dispatch_queue_t globalDispatchQueueDefault     = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t globalDispatchQueueLow         = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    dispatch_queue_t globalDispatchQueueBackgroungn = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
  • dispatch_set_target_queue
    dispatch_queue_create创建的不论是串行还是并行队列,都使用与默认优先级的Global Dispatch Queue相同的执行优先级的线程.
    dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("io.github.junne.serialTestDispatchQueue", NULL);
    dispatch_queue_t globalDispatchQueueBackgroud = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackgroud);
    dispatch_async(mySerialDispatchQueue, ^{
        NSLog(@"mySerialDispatchQueue");
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"Default Priority");
    });

执行顺序为先Default Priority后mySerialDiapatchQueue.

  • dispatch_after
    一般可用于延迟多少时间后将一些任务添加到队列,经常用于延后执行操作:
    NSLog(@"dispatchAfter One");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"dispatchAfter Two");
    });

上述代码用来延迟三秒后执行打印dispatchAfter Two.

  • Dispatch Group
    当想要队列中追加的操作处理全部结束时再进行某项操作时,可以使用一个Serial Dispatch Queue将想要执行的操作追加到最后即可.但当使用并行队列或者多个Dispatch Queue时可以使用Dispatch Group:
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"Group First");
    });
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"Group Second");
    });
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"Group Third");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"Group All Done");
    });

当group里面的操作都完成时就会调用dispatch_group_notify里面的操作.

  • dispatch_barrier_async
    当访问数据库时可以用Serial Dispatch Queue来避免数据竞争.但当想要高效地并行访问数据库时可以使用dispatch_barrier_async:
    dispatch_queue_t queue = dispatch_queue_create("io.guthub.junne.barrier", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"Reading First");
    });
    dispatch_async(queue, ^{
        NSLog(@"Reading Second");
    });
    dispatch_async(queue, ^{
        NSLog(@"Reading Third");
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"Writing First");
    });
    dispatch_async(queue, ^{
        NSLog(@"Reading Fourth");
    });
    dispatch_async(queue, ^{
        NSLog(@"Reading Fifth");
    });    dispatch_async(queue, ^{
        NSLog(@"Reading Sixth");
    });

程序会在执行dispatch_barrier_async之前,完成队列中的所有操作,继而执行barrier里面的内容,当barrier里面的内容执行完毕后再去执行之后的内容.

  • dispatch_sync
    dispatch_async中的async意味着asynchronous即非同步,就是将block非同步地追加到指定的Dispatch Queue中,不做任何等待.
    dispatch_sync意味着synchronous即同步,就是将block同步地追加到指定的Dispatch Queue中,在追加结束之前,会一直等待.
    dispatch_sync稍有不慎就会引发死锁:
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_sync(mainQueue, ^{
        NSLog(@"Ha ha ha ha...");
    });

在主线程中执行指定的block,并等待其结束,而主线程中这在执行这些源代码,因此无法执行追加到Main Dispatch Queue的Block.

  • dispatch_apply
    dispatch_apply是dispatch_sync和Dispatch Group的关联API.此函数按指定的次数将block追加到制定的队列中,并等待全部处理结束:
    NSArray *testArray = @[@"first",@"second",@"third",@"fourth",@"fifth"];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply([testArray count], queue, ^(size_t index) {
        NSLog(@"%zu: %@", index, [testArray objectAtIndex:index]);
    });
    NSLog(@"TestApple Done");
  • dispatch_suspend && dispatch_resume
    当我们希望不执行已追加队列中的操作时,只要挂起Dispatch Queue即可,当需要时在恢复即可:
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"Suspend Start");
        dispatch_suspend(queue);
        NSLog(@"Susupend");
        sleep(2);
        dispatch_resume(queue);
        NSLog(@"Resume");
    });
  • Dispatch Semaphore
    直接上例子:
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            [mutableArray addObject:[NSNumber numberWithInt:i]];
            dispatch_semaphore_signal(semaphore);
        });
    }
    NSLog(@"mutableArray = %@", mutableArray);
  • dispatch_once
    用来保证在应用程序中只执行一次指定处理的API.常用来创建单例:
    static ViewController *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[ViewController alloc] init];
    });
    return instance;

参考及拓展阅读:

相关文章

  • iOS-多线程:GCD

    GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(6种不同组合区别) GCD 线程间的通信...

  • iOS多线程--彻底学会多线程之『GCD』

    GCD 文章目录 GCD简介 任务和队列 GCD的使用步骤 队列的创建方法 任务的创建方法 GCD的基本使用 并行...

  • iOS GCD

    GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(六种组合不同区别,队列嵌套情况区别,相互...

  • 多线程之GCD

    GCD介绍 1、GCD简介 2、GCD任务和队列 3、GCD 的基本使用 4、GCD 线程间的通信 5、GCD 的...

  • iOS多线程--GCD篇

    GCD 文章目录GCD简介任务和队列GCD的使用步骤队列的创建方法任务的创建方法GCD的基本使用并行队列 + 同步...

  • iOS 关于GCD很详细的描述

    那为什么我们要使用 GCD 呢? 因为使用 GCD 有很多好处啊,具体如下:GCD 可用于多核的并行运算;GCD ...

  • GCD多线程详解

    1. GCD 简介 2. GCD 任务和队列 3. GCD 的使用步骤 4. GCD 的基本使用(6种不同组合区别...

  • iOS GCD的使用

    什么是GCD了解GCD前,需要了解的基础知识GCD的使用使用注意事项 -GCD学习前铺垫-什么是GCDGCD (G...

  • iOS - GCD

    目录 GCD简介 GCD核心概念 GCD队列的使用 GCD的常见面试题 GCD简介 Grand Central D...

  • iOS GCD的使用

    本文的主要内容是: 什么是GCD 了解GCD前,需要了解的基础知识 GCD的使用 使用注意事项 -GCD学习前铺垫...

网友评论

    本文标题:GCD的使用

    本文链接:https://www.haomeiwen.com/subject/gbtslttx.html