zoukankan      html  css  js  c++  java
  • GCD的使用

    Dispatch Queue
    Dispatch Queue是用来执行任务的队列,是GCD中最基本的元素之一。
    Dispatch Queue分为两种:
    Serial Dispatch Queue,按添加进队列的顺序(先进先出)一个接一个的执行
    Concurrent Dispatch Queue,并发执行队列里的任务
    简而言之,Serial Dispatch Queue只使用了一个线程,Concurrent Dispatch Queue使用了多个线程(具体使用了多少个,由系统决定)。
    可以通过两种方式来获得Dispatch Queue
    //创建串行队列
    dispatch_queue_t serialQueue=dispatch_queue_create("com.xxx", DISPATCH_QUEUE_SERIAL);

    //创建并行行队列
    dispatch_queue_t concurrentQueue=dispatch_queue_create("com.xxx", DISPATCH_QUEUE_CONCURRENT);


    第一个参数是队列的名称,一般是使用倒序的全域名。虽然可以不给队列指定一个名称,但是有名称的队列可以让我们在遇到问题时更好调试;当第二个参数为nil时返回Serial Dispatch Queue,如上面那个例子,当指定为DISPATCH_QUEUE_CONCURRENT时返回Concurrent Dispatch Queue。
    第二种方式是直接获取系统提供的Dispatch Queue。
    要获取的Dispatch Queue无非就是两种类型:
    Main Dispatch Queue
    Global Dispatch Queue / Concurrent Dispatch Queue
    一般只在需要更新UI时我们才获取Main Dispatch Queue,其他情况下用Global Dispatch Queue就满足需求了:
    //主线程
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //子线程
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_after
    dispatch_after能让我们添加进队列的任务延时执行,比如想让一个Block在10秒后执行:
    double delayInSeconds = 10.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    NSLog(@"电充好了");
    });
    NSEC_PER_SEC表示的是秒数,它还提供了NSEC_PER_MSEC表示毫秒。
    这句dispatch_after的真正含义是在10秒后把任务添加进队列中,并不是表示在10秒后执行

    dispatch_group
    //执行组 集团
    可能经常会有这样一种情况:我们现在有3个Block要执行,我们不在乎它们执行的顺序,我们只希望在这3个Block执行完之后再执行某个操作。这个时候就需要使用dispatch_group了:
    dispatch_group_t g=dispatch_group_create();
    dispatch_group_async(g, concurrentQueue, ^(void){
    NSLog(@"电充好了");
    });
    dispatch_group_notify(g, concurrentQueue, ^(void){
    NSLog(@"电充好了1");
    });
    输出的顺序与添加进队列的顺序无关,因为队列是Concurrent Dispatch Queue,但“completed”的输出一定是在最后的:电充好了1
    除了使用dispatch_group_notify函数可以得到最后执行完的通知外,还可以使用
    需要注意的是,dispatch_group_wait实际上会使当前的线程处于等待的状态,也就是说如果是在主线程执行dispatch_group_wait,在上面的Block执行完之前,主线程会处于卡死的状态。可以注意到dispatch_group_wait的第二个参数是指定超时的时间,如果指定为DISPATCH_TIME_FOREVER(如上面这个例子)则表示会永久等待,直到上面的Block全部执行完,除此之外,还可以指定为具体的等待时间,根据dispatch_group_wait的返回值来判断是上面block执行完了还是等待超时了。
    dispatch_group_t g=dispatch_group_create();
    dispatch_group_async(g, concurrentQueue, ^(void){
    NSLog(@"电充好了");
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
    NSLog(@"电充好了1");

    dispatch_barrier_async
    dispatch_barrier_async就如同它的名字一样,在队列执行的任务中增加“栅栏”,在增加“栅栏”之前已经开始执行的block将会继续执行,当dispatch_barrier_async开始执行的时候其他的block处于等待状态,dispatch_barrier_async的任务执行完后,其后的block才会执行

    - (void)writeFilek{
    [[NSUserDefaults standardUserDefaults]setInteger:7 forKey:@"integer"];
    }
    - (void)readFile{
    NSLog(@"%i",[[NSUserDefaults standardUserDefaults]integerForKey:@"integer"]);
    }

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(globalQueue, ^(void){
    [self readFile];
    });
    dispatch_async(globalQueue, ^(void){
    [self readFile];
    });
    dispatch_async(globalQueue, ^(void){
    [self readFile];
    });
    dispatch_barrier_async(globalQueue, ^(void){
    [self writeFilek];
    [self readFile];
    });
    dispatch_async(globalQueue, ^(void){
    [self readFile];
    });
    dispatch_async(globalQueue, ^(void){
    [self readFile];
    });
    dispatch_async(globalQueue, ^(void){
    [self readFile];
    });

    由于这个队列是一个Concurrent Dispatch Queue,能同时并发多少线程是由系统决定的,如果添加dispatch_barrier_async的时候,其他的block(包括上面4个block)还没有开始执行,那么会先执行dispatch_barrier_async里的任务,其他block全部处于等待状态。如果添加dispatch_barrier_async的时候,已经有block在执行了,那么dispatch_barrier_async会等这些block执行完后再执行。

    dispatch_apply
    dispatch_apply会将一个指定的block执行指定的次数。如果要对某个数组中的所有元素执行同样的block的时候,这个函数就显得很有用了,用法很简单,指定执行的次数以及Dispatch Queue,在block回调中会带一个索引,然后就可以根据这个索引来判断当前是对哪个元素进行操作:
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_apply(10, globalQueue, ^(size_t tem){
    NSLog(@"%lu",tem);
    });
    NSLog(@"completed");
    由于是Concurrent Dispatch Queue,不能保证哪个索引的元素是先执行的,但是“completed”一定是在最后打印,因为dispatch_apply函数是同步的,执行过程中会使线程在此处等待,所以一般的,我们应该在一个异步线程里使用dispatch_apply函数:

    dispatch_suspend / dispatch_resume
    某些情况下,我们可能会想让Dispatch Queue暂时停止一下,然后在某个时刻恢复处理,这时就可以使用dispatch_suspend以及dispatch_resume函数:
    //暂停
    dispatch_suspend(globalQueue)
    //恢复
    dispatch_resume(globalQueue)
    暂停时,如果已经有block正在执行,那么不会对该block的执行产生影响。dispatch_suspend只会对还未开始执行的block产生影响。

  • 相关阅读:
    SSL JudgeOnline 1194——最佳乘车
    SSL JudgeOnline 1457——翻币问题
    SSL JudgeOnlie 2324——细胞问题
    SSL JudgeOnline 1456——骑士旅行
    SSL JudgeOnline 1455——电子老鼠闯迷宫
    SSL JudgeOnline 2253——新型计算器
    SSL JudgeOnline 1198——求逆序对数
    SSL JudgeOnline 1099——USACO 1.4 母亲的牛奶
    SSL JudgeOnline 1668——小车载人问题
    SSL JudgeOnline 1089——USACO 1.2 方块转换
  • 原文地址:https://www.cnblogs.com/kkkblog/p/4209042.html
Copyright © 2011-2022 走看看