讲在前面
GCD、NSOperation、NSThread哪个你比较中意呢?我用的GCD很顺手啊,相信很多人也和我一样,会对GCD熟悉的不能再熟悉,原理巴拉多网上也是一堆一堆的,这里咱们就讲讲实战好了。
GCD分类
按照类型分为: 串行(serial queue)和并行(concurrent queue)
按照系统提供api分为: 主线程(main queue)、全局线程(global queue)和自定义线程(custom queue)
- 其中main queue通过dispatch_get_main_queue()获取,是主线程,属于serial queue;
- global queue通过dispatch_get_global_queue()获取,是全局队列,属于concurrent queue;
- custom queue 通过dispatch_queue_create()方法定义
需要注意的几点:
-
serial queue是串行队列,串行队列的特点是FIFO(first in first out),队列中的第一个任务完成了,才能执行第二个任务,第二个任务执行完成后开始执行第三个任务,以此类推。所以理论上需要数据安全的操作可以放到这个队列中完成,例如数据库的写操作、需要锁机制的操作,也可以达到目的。当然,如果你在serial queue里面添加的sync任务,就要明白,他可能是会阻塞线程的。
-
concurrent queue是并行队列,他的特点是第一个任务开始执行后,马上可以开始第二个任务,第三个etc. 但是先执行不代表先出栈(任务执行完毕),后执行也不代表后出栈。通常,关于数据的读操作、多图片上传等只考虑并发,不考虑顺序的操作都是可以放到这个队列中的。
GCD相关API
dispatch_serial_queue
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSLog(@"1");
});
dispatch_async(serialQueue, ^{
NSLog(@"2");
});
dispatch_async(serialQueue, ^{
NSLog(@"3");
});
dispatch_async(serialQueue, ^{
NSLog(@"4");
});
dispatch_async(dispatch_get_main_queue(), ^{
self.title = @"hello";
});
输出结果:
2018-07-15 19:55:36.940535+0800 GCDDemo[12328:651362] 1
2018-07-15 19:55:36.940688+0800 GCDDemo[12328:651362] 2
2018-07-15 19:55:36.940781+0800 GCDDemo[12328:651362] 3
2018-07-15 19:55:36.940889+0800 GCDDemo[12328:651362] 4
dispatch_concurrent_queue
dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
NSLog(@"1");
});
dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
NSLog(@"2");
});
dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
NSLog(@"3");
});
dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
NSLog(@"4");
});
dispatch_group_async(self.groupQueue,dispatch_get_global_queue(0, 0), ^{
NSLog(@"5");
});
dispatch_group_notify(self.groupQueue, dispatch_get_global_queue(0, 0), ^{
NSLog(@"group queue end.");
});
输出结果:
2018-07-15 20:00:21.782358+0800 GCDDemo[12418:657731] 2
2018-07-15 20:00:21.782368+0800 GCDDemo[12418:657728] 3
2018-07-15 20:00:21.782378+0800 GCDDemo[12418:657732] 4
2018-07-15 20:00:21.782358+0800 GCDDemo[12418:657729] 1
2018-07-15 20:00:21.782505+0800 GCDDemo[12418:657731] 5
2018-07-15 20:00:21.782612+0800 GCDDemo[12418:657731] group queue end.
dispatch_barrier_async GCD的栅栏方法
栅栏前加入队列的任务全部执行完之后,才会执行栅栏任务,栅栏任务执行完后再执行栅栏后加入队列的任务。
dispatch_queue_t queue = dispatch_queue_create("queue.barrier.tmp", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"%d %@",i,[NSThread currentThread]);
});
if(i == 5) {
dispatch_barrier_async(queue, ^{
NSLog(@"barrier %d %@",i,[NSThread currentThread]);
});
}
}
输出结果:
2018-07-16 10:51:54.247399+0800 GCDDemo[63628:24167474] 2 <NSThread: 0x60c00026ff40>{number = 3, name = (null)}
2018-07-16 10:51:54.247406+0800 GCDDemo[63628:24167475] 3 <NSThread: 0x60400007fb80>{number = 4, name = (null)}
2018-07-16 10:51:54.247410+0800 GCDDemo[63628:24167472] 4 <NSThread: 0x600000461340>{number = 7, name = (null)}
2018-07-16 10:51:54.247414+0800 GCDDemo[63628:24167473] 1 <NSThread: 0x6080002607c0>{number = 6, name = (null)}
2018-07-16 10:51:54.247410+0800 GCDDemo[63628:24167471] 0 <NSThread: 0x60000027ed40>{number = 5, name = (null)}
2018-07-16 10:51:54.247411+0800 GCDDemo[63628:24167499] 5 <NSThread: 0x60c0002700c0>{number = 8, name = (null)}
2018-07-16 10:51:54.247900+0800 GCDDemo[63628:24167499] barrier 5 <NSThread: 0x60c0002700c0>{number = 8, name = (null)}
2018-07-16 10:51:56.250672+0800 GCDDemo[63628:24167473] 9 <NSThread: 0x6080002607c0>{number = 6, name = (null)}
2018-07-16 10:51:56.250669+0800 GCDDemo[63628:24167499] 6 <NSThread: 0x60c0002700c0>{number = 8, name = (null)}
2018-07-16 10:51:56.250669+0800 GCDDemo[63628:24167474] 7 <NSThread: 0x60c00026ff40>{number = 3, name = (null)}
2018-07-16 10:51:56.250679+0800 GCDDemo[63628:24167471] 8 <NSThread: 0x60000027ed40>{number = 5, name = (null)}
- 这里有必要来分析一下,barrier前面开启了六个新线程,从3开始,因为1和2 分别分配给了主线程和全区队列。当线程栅栏前面的任务全部执行完毕之后,线程空出来了,最后一个线程是8,紧接着去执行栅栏任务,栅栏任务执行完毕之后,线程抖空出来了,再从中找四个空线程去完成接下来的四个异步队列任务。
dispatch_group_t
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"group start");
dispatch_group_async(group, queue, ^{
dispatch_group_enter(group); // @1
NSLog(@"group one start");
dispatch_async(queue, ^{
sleep(1);
NSLog(@"group one finish");
dispatch_group_leave(group);//@2
});
});
dispatch_group_notify(group, queue, ^{
NSLog(@"group finished");
});
-
1(dispatch_group_enter)和2(dispatch_group_leave)两个方法是配对出现的,机制类似于GCD的信号量,enter的时候任务书+1,leave的时候任务数-1,当任务数为0 的时候会调用dispatch_group_notify的block内容执行
dispatch_group_async 就相当于 dispatch_group_enter(group); dispatch_async(queue, ^{ dispatch_group_leave(group); });
dispatch_after 延时调用
NSLog(@"%@",[NSDate date]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSDate date]);
NSLog(@"hello world");
});
输出结果:
2018-07-16 11:53:52.032397+0800 GCDDemo[64332:24322897] Mon Jul 16 11:53:52 2018
2018-07-16 11:53:54.229555+0800 GCDDemo[64332:24322897] Mon Jul 16 11:53:54 2018
2018-07-16 11:53:54.229737+0800 GCDDemo[64332:24322897] hello world
别着急还有很多~
网友评论