1. 创建dispatch_queue_t
需求:我们要打印10000个数字,在打印的同时显示一个红色的视图
不使用GCD
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 10000; i++) {
NSLog(@"%d",i);
}
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
[view setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
[self.view addSubview:view];
view.backgroundColor = [UIColor redColor];
}
上面的代码,所有的操作都是在主线程的,主线程会先把10000个数字打印完再显示图片,这样肯定不是我们想要的;
使用GCD
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t myQueue = dispatch_queue_create("com.gcd.myQueue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myQueue, ^{
for (int i = 0; i < 10000; i++) {
NSLog(@"%d",i);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"---finished---");
});
});
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
[view setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
[self.view addSubview:view];
view.backgroundColor = [UIColor redColor];
}
显示图片的同时也在打印数字,这才是我们想要的效果
2. dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1s later.");
});
注意:dispatch_after并不是表示几秒后执行Block中的代码;它表示的是几秒后,将Block追加到指定的Dispatch Queue中。
我们看下面这段代码
- (void)viewDidLoad {
[super viewDidLoad];
//事件1
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"1s later.");
});
//事件2
for (int i = 0; i < 20000; i++) {
NSLog(@"%d",i);
}
}
事件1的代码一般简化为:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1s later.");
});
结果会发现,1s later是在所有的数字打印完了才输出的,而不是固定1s后输出的;这也验证了上面的说法。
如果要更准确一点,可以把这两个事件分到不同的Queue中执行,互不干涉,互不等待,可以相对准确地来触发定时事件;
尽管如此,也不能精确地表示一定是1s后执行Block中代码,这涉及到Runloop
3. dispatch_group
如果我们希望Queue中的多个处理全部结束后再执行结束处理,我们有2种做法
- 当只有一个Serial Queue时,可以把所有的处理都追加到Serial Queue中顺序执行即可;当多个处理完成后,再执行结束处理
- 如果是一个Concurrent Queue,其中的多个处理都是乱序的,我们不知道什么时候能完成所有的处理,所以我们需要一个分隔符,用以确定除结束操作外的所有处理都结束了,我们才可以进行结束处理;dispatch_group就是一个这样的分隔符
需求:数组array里有30000条数据,不要求数字顺序,全部打印出来即可,打印完成后,输出Read finished.
- Serial Queue
dispatch_queue_t serialQueue = dispatch_queue_create("com.gcd.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
for (int i = 0; i < 10000; i++) {
NSLog(@"%@", array[i]);
}
});
dispatch_async(serialQueue, ^{
for (int i = 10000; i < 20000; i++) {
NSLog(@"%@", array[i]);
}
});
dispatch_async(serialQueue, ^{
for (int i = 20000; i < 30000; i++) {
NSLog(@"%@", array[i]);
}
});
dispatch_async(serialQueue, ^{
NSLog(@"Read finished.");
});
结果

- Concurrent Queue
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, concurrentQueue, ^{
for (int i = 0; i < 10000; i++) {
NSLog(@"%@",array[i]);
}
});
dispatch_group_async(group, concurrentQueue, ^{
for (int i = 10000; i < 20000; i++) {
NSLog(@"%@",array[i]);
}
});
dispatch_group_async(group, concurrentQueue, ^{
for (int i = 20000; i < 30000; i++) {
NSLog(@"%@",array[i]);
}
});
dispatch_group_notify(group, concurrentQueue, ^{
NSLog(@"Read finished.");
});
结果

或者使用dispatch_group_wait
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, concurrentQueue, ^{
for (int i = 0; i < 10000; i++) {
NSLog(@"%@",array[i]);
}
});
dispatch_group_async(group, concurrentQueue, ^{
for (int i = 10000; i < 20000; i++) {
NSLog(@"%@",array[i]);
}
});
dispatch_group_async(group, concurrentQueue, ^{
for (int i = 20000; i < 30000; i++) {
NSLog(@"%@",array[i]);
}
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"Read finished");
dispatch_group_wait
有两个参数,第一个是指定group,第二个表示如果group里的任务没有执行完成,要等待多久?DISPATCH_TIME_FOREVER
就是表示:如果group中的任务没有执行完成,就一直等待。
4. dispatch_barrier_async·
- 对同个数据读取可以多个并行执行;
- 对同个数据进行多个写入操作是不能并行执行的,因为我们无法确定并行执行的顺序;
- 对同个数据进行读取和写入是不能并行执行的,这样会导致数据出错
为了避免数据错乱,且要高效地完成操作,我们可以采用dispatch_barrier_async
需求:可变数组array中有0-299共300个数据,我们需要读取最后三条数据,并且插入300-399后,再读取一次最后三条数据
- 如果不用
dispatch_barrier_async
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 300; i ++) {
[array addObject:@(i)];
}
dispatch_queue_t queue = dispatch_queue_create("com.testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 1] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 2] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 3] intValue]);
});
//写入操作
dispatch_async(queue, ^{
NSLog(@"---------Begin write----------");
for (int i = 300; i < 400; i ++) {
[array addObject:@(i)];
}
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 1] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 2] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 3] intValue]);
});
结果
2019-05-15 09:55:43.535947+0800 GCD[2571:121141] 299
2019-05-15 09:55:43.535949+0800 GCD[2571:121140] 298
2019-05-15 09:55:43.535973+0800 GCD[2571:121138] 297
2019-05-15 09:55:43.535999+0800 GCD[2571:121139] ---------Begin write----------
2019-05-15 09:55:43.536086+0800 GCD[2571:121141] 299
2019-05-15 09:55:43.536087+0800 GCD[2571:121140] 298
2019-05-15 09:55:43.536132+0800 GCD[2571:121138] 299
开始插入数据后,读取到的数据是乱序的,显然不是我们想要的效果
- 使用
dispatch_barrier_async
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 300; i ++) {
[array addObject:@(i)];
}
dispatch_queue_t queue = dispatch_queue_create("com.testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 1] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 2] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 3] intValue]);
});
//上面的读取操作可以并行执行,但是写入操作必须要单独执行
dispatch_barrier_async(queue, ^{
NSLog(@"---------Begin write----------");
for (int i = 300; i < 400; i ++) {
[array addObject:@(i)];
}
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 1] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 2] intValue]);
});
dispatch_async(queue, ^{
NSLog(@"%d", [array[array.count - 3] intValue]);
});
结果
2019-05-15 09:53:12.712380+0800 GCD[2495:115079] 299
2019-05-15 09:53:12.712393+0800 GCD[2495:115077] 298
2019-05-15 09:53:12.712408+0800 GCD[2495:115078] 297
2019-05-15 09:53:12.712537+0800 GCD[2495:115078] ---------Begin write----------
2019-05-15 09:53:12.712618+0800 GCD[2495:115078] 399
2019-05-15 09:53:12.712629+0800 GCD[2495:115079] 398
2019-05-15 09:53:12.712636+0800 GCD[2495:115077] 397
是我们想要的效果
我这里的读取都比较简单,假设需要大量的读取操作,依然可以按照这样的思路设计。
网友评论