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

来源:互联网 发布:淘宝开店认证哪里复核 编辑:程序博客网 时间:2024/05/04 20:01

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
输入输出控制 具体细节我们会在后面中探讨.

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

1 0
原创粉丝点击