您的位置:首页 > 移动开发 > IOS开发

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

2015-12-25 10:29 218 查看

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

输入输出控制 具体细节我们会在后面中探讨.

欢迎大家来积极讨论呦~~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios ios开发 gcd