iOS开发之浅谈GCD的使用(二)

iOS开发之浅谈GCD的使用(二)

系统提供的global队列

上次说到系统给我们提供了四个队列, 分别是global队列的四种优先级. 我们打印四个优先级队列的地址, 可以看到四个优先级队列的地址是不同的, 所以这是四个不同的队列, 然后我们在同一个程序不同的地方去打印, 发现同优先级的队列的地址是相同的. 所以可以得出, 在一个程序中, 在任何地方调用dispatch_get_global_queue 得到相同优先级的队列, 都是同一个.(类似于单例)

在系统的global队列中追加任务的方法是

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"%@", globalDefaultPriority);
    });

dispatch_after与dispatch_time_t

这个函数的目的是, 在一段时间后把block中的任务追加到一个队列中, 经常被用作延迟执行. 例如: 我要把一段代码在2秒后放入主队列中执行.

       //建立一个dispatch_time_t, 代表着从现在开始计算, 2秒后
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
       //这段代码就是将输出语句在两秒后追加进主队列
       dispatch_after(time, dispatch_get_main_queue(), ^{
        NSLog(@"%@", globalHighPriority); 
    }); 

需要注意一点, 这个函数是N秒后将一段代码追加进队列中, 并不是N秒后直接执行, 加入将一个线程睡眠2秒, 然后将一个输出语句在2秒后追加进这个线程, 那么这个输出语句将会在4秒后才执行.

group 组队列

在开发中, 我们经常碰到这种情况, 我们开辟了三个线程, 然后我们需要等到这几个线程都执行完了后, 调用一段代码, 而这三个线程是用的并发队列, 我们并不知道哪个是最后一个执行, 这个时候我们就要用到group组队列, 使用group我们可以监听到一组队列中所有的任务是不是都执行完.

    //我们先获取到一个并发队列
 dispatch_queue_t globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //创建一个组
    dispatch_group_t group = dispatch_group_create();
    //向这个队列追加两个任务
        dispatch_group_async(group, globalQueueDefault, ^{
        NSLog(@"block1");
    });
    dispatch_group_async(group, globalQueueDefault, ^{
        NSLog(@"block2");
    });
    //在两个任务都执行完之后, 才去输出结束处理, 在组里面的任务执行结束之后会调用这个方法dispatch_group_notify
      dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"结束处理");
    });

dispatch_barrier_async

我们对本地文件进行读写的时候 不能用并行同时进行读取和写入 这样会造成很多问题 例如:数据竞争问题 由于可能在写入之前先读取 所以可能造成数据混乱还有可能导致程序异常结束 但是我们可以进行同时读取的操作 前提是写入必须在读取之前 所以可以将读取处理追加到Concurrent Queue中 写入处理在任何一个读取处理都没有进行之前 追加到Serial Queue中 虽然可以用Queue 和dispatch_set_target_queue实现 但是很麻烦 所以系统给我们提供了 dispatch_barrier_async 这个函数会等待追加到Concurrent Dispatch Queue上得并行执行全部结束后 再将指定的处理追加到这个Concurrent Dispatch Queue上 等这个追加处理完成后再将Concurrent Dispatch Queue恢复为一般的动作

先说一下错误的写法

    //这样写会出现那样的问题(错误的)
    dispatch_async(global, ^{
        NSLog(@"读取1");
    });
    dispatch_async(global, ^{
        NSLog(@"读取2");
    });
    dispatch_async(global, ^{
        NSLog(@"读取3");
    });
    dispatch_async(global, ^{
        NSLog(@"写入");
    });
    dispatch_async(global, ^{
        NSLog(@"读取4");
    });

以上的写法会造成读取与写入混乱 , 会产生很严重的后果.
正确的写法应该是:

    dispatch_async(global, ^{
        NSLog(@"读取1");
    });
    dispatch_async(global, ^{
        NSLog(@"读取2");
    });
    dispatch_async(global, ^{
        NSLog(@"读取3");
    });
    dispatch_barrier_async(global, ^{
        NSLog(@"写入1");
    });
    dispatch_async(global, ^{
        NSLog(@"读取4");
    });

以上是正确写法, 在写入时使用了dispatch_barrier_async, 这样系统会等待读取1、读取2、读取3这三个任务都执行结束之后再将写入1这个任务追加进队列中, 等写入1执行完毕, 再将队列恢复为一般的状态.

semaphore GCD的引用计数

semaphore是持有计数信号 类似过马路的手旗 可以通过时举起 不可以通过时放下手旗 Dispatch Semaphore中 使用计数来实现该功能, 计数为0时等待, 计数为1或者大于1的时候 减去1而不等待

以下写法是错误的, 可能会产生崩溃.

      for (int i = 0; i < 1000; i++) {
        dispatch_async(global, ^{
            [arr addObject:[NSNumber numberWithInt:i]];
        });
    }

以下的写法是正确的 , 使用Semaphore来控制线程的执行.

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    for (int i = 0; i < 1000; i++) {
        dispatch_async(global, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            [arr addObject:[NSNumber numberWithInt:i]];
            dispatch_semaphore_signal(semaphore);
        });
    }

还有另一个用法, dispatch I/O
输入输出控制 具体细节我们会在后面中探讨.

欢迎大家来积极讨论呦~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值