Queue
- main queue: 主线程队列,串行队列。一般用于刷新UI。
- global queue: 全局队列,并行队列。
- custom queue: 自定义队列。
*1
2
3
4
5
6
7
8
9// 一般用法
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 100000; i++) {
NSLog(@"%zd", i);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"刷新UI");
});
});
自定义队列
串行队列
同步运行
1
2
3
4
5
6
7
8
9
10
11
12dispatch_queue_t serialQueue = dispatch_queue_create("kl.serialQueue", DISPATCH_QUEUE_SERIAL);
for (int j = 0; j < 3; j++) {
dispatch_sync(serialQueue, ^{
for (int i = 0 ; i < 3; i++) {
NSLog(@"current Thread %@ -- concurrentQueue %zd -- dispatch_async %zd",[NSThread currentThread] ,j, i);
}
});
NSLog(@"run in mainQueue");
}
// 运行结果分析: 线程指针地址相同,是同一个线程;输出结果按序输出,串行队列先进先出。
// `run in mainQueue` 出现在for循环之后即dispatch_sync任务执行完之后,因为串行队列同步运行,阻塞主线程。
// 在这里发现创建的线程和主线程地址相同,说明串行队列同步运行是直接在主线程中运行的!异步运行
1
2
3
4
5
6
7
8
9
10
11dispatch_queue_t serialQueue = dispatch_queue_create("kl.serialQueue", DISPATCH_QUEUE_SERIAL);
for (int j = 0; j < 3; j++) {
dispatch_async(serialQueue, ^{
for (int i = 0 ; i < 3; i++) {
NSLog(@"current Thread %@ -- concurrentQueue %zd -- dispatch_async %zd",[NSThread currentThread] ,j, i);
}
});
NSLog(@"run in mainQueue");
}
// 运行结果分析: 线程指针地址相同,是同一个线程;输出结果按序输出,串行队列先进先出。
// `run in mainQueue` 出现随机,因为是异步运行,不阻塞主线程。
并行队列
同步运行
1
2
3
4
5
6
7
8
9
10
11
12
13dispatch_queue_t concurrentQueue = dispatch_queue_create("kl.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
for (int j = 0; j < 3; j++) {
dispatch_sync(concurrentQueue, ^{
for (int i = 0 ; i < 3; i++) {
NSLog(@"current Thread %@ -- concurrentQueue %zd -- dispatch_async %zd",[NSThread currentThread] ,j, i);
}
});
NSLog(@"run in mainQueue current Thread %@", [NSThread currentThread]);
}
// 运行结果分析: 线程地址相同,且与主线程队列地址相同,
// 结合串行队列同步运行与串行队列异步运行结果来看,同步运行时线程都是在主线程上运行,不开辟新的线程。
// 运行结果与串行队列同步运行相同异步运行
1
2
3
4
5
6
7
8
9
10
11
12
13dispatch_queue_t concurrentQueue = dispatch_queue_create("kl.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
for (int j = 0; j < 3; j++) {
dispatch_async(concurrentQueue, ^{
for (int i = 0 ; i < 3; i++) {
NSLog(@"current Thread %@ -- concurrentQueue %zd -- dispatch_async %zd",[NSThread currentThread] ,j, i);
}
});
NSLog(@"run in mainQueue current Thread %@", [NSThread currentThread]);
}
// 运行结果分析: 输出结构乱序,因为是并行的异步执行,
// 不能决定谁先谁后,且发现线程地址不同,说明开了多条线程执行队列,
// `run in mainQueue` 出现随机,因为是异步运行,不阻塞主线程。
总结:
- dispatch_sync 并不会开辟新的线程执行任务,所以不管是串行队列还是并行队列其实都在一个线程(mainQueue也在主线程)中运行,且它是同步的,所以阻塞主线程,一定得队列任务完成之后才会执行之后的任务!
- dispatch_async 会异步的运行队列任务,但是串行队列只在一个线程中,所以只是不阻塞主线程,但是还是遵行串行队列FIFO(先进先出)执行任务, 而并行队列会开多条线程进行异步执行任务,效率更高!
dispatch_barrier
在 dispatch_barrier
之后的任务总是会在 dispatch_barrier
之前的任务执行完之后在执行
dispatch_barrier_sync
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23for (int i = 0; i < 3; i++) {
dispatch_async(self.concurrentQueue, ^{
NSLog(@"current Thread %@ -- dispatch_async_1 %zd",[NSThread currentThread], i);
});
}
NSLog(@"dispatch_async_1_main");
for (int i = 0; i < 3; i++) {
dispatch_barrier_sync(self.concurrentQueue, ^{
NSLog(@"current Thread %@ -- dispatch_barrier_sync %zd",[NSThread currentThread], i);
if (i == 4) {
NSLog(@"dispatch_barrier_sync finished");
}
});
}
NSLog(@"dispatch_barrier_sync_main");
for (int i = 0; i < 3; i++) {
dispatch_async(self.concurrentQueue, ^{
NSLog(@"current Thread %@ -- dispatch_async_2 %zd",[NSThread currentThread], i);
});
}
NSLog(@"dispatch_async_2_main");
// 结果分析 先并发异步执行 dispatch_async_1,
// 在执行 dispatch_barrier_sync ,最后并发异步执行 dispatch_async_2, dispatch_barrier_sync 会阻塞主线程dispatch_barrier_async
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25for (int i = 0; i < 3; i++) {
dispatch_async(self.concurrentQueue, ^{
NSLog(@"current Thread %@ -- dispatch_async_1 %zd",[NSThread currentThread], i);
});
}
NSLog(@"dispatch_async_1_main");
for (int i = 0; i < 3; i++) {
dispatch_barrier_async(self.concurrentQueue, ^{
NSLog(@"current Thread %@ -- dispatch_barrier_async %zd",[NSThread currentThread], i);
if (i == 2) {
NSLog(@"dispatch_barrier_sync finished");
}
});
}
NSLog(@"dispatch_barrier_sync_main");
for (int i = 0; i < 3; i++) {
dispatch_async(self.concurrentQueue, ^{
NSLog(@"current Thread %@ -- dispatch_async_2 %zd",[NSThread currentThread], i);
});
}
NSLog(@"dispatch_async_2_main");
// 结果分析: 首先它仍然会阻拦 dispatch_barrier_async 之后的任务等之前任务执行完之后再执行,
// 其次他由于是异步的所以不阻塞主线程,
// 但是我发现 `dispatch_barrier_async`里面执行的认为在一条线程中执行,且按顺序执行的!
// 所以我们做耗时操作的时候尽量不要放在`dispatch_barrier_async`中执行,因为虽然他不阻塞主线程队列,但是会阻塞我们自创的队列啊!
注意:
dispatch_barrier
不要用在global queue
中,因为dispatch_barrier
只使用在一条并行队列中,而global queue
是每次系统分配一个并行队列(可能是不同的),所以没有意义!dispatch_barrier_async
里面执行的认为在一条线程中执行,且按顺序执行的!所以我们做耗时操作的时候尽量不要放在dispatch_barrier_async
中执行,因为虽然他不阻塞主线程队列,但是会阻塞我们自创的队列!- NSDictionary: 线程安全, 但是NSMutableDictionary: 不是线程安全的,所以我们可以使用 dispatch_barrier_async 来保证 NSMutableDictionary 线程安全!(Get&&Set)
dispatch_semaphone: 信号量(用于并发控制)
- dispatch_semaphore_create(3)
创建信号量,传入一个大于等于0的long型整数(比作停车位,有了停车位才能停车) - dispatch_semaphore_signal(semaphone)
- 传入一个信号量,执行一次,增加一次semaphone计数(可以这么理解: 一辆车开走了,然后这个停车位就空出来了,算作增加一个停车位);
- 返回值为0时表示当前并没有线程等待其处理的信号量;
- 返回值不为0时,表示其当前有(一个或多个)线程等待其处理的信号量,并且该函数唤醒了一个等待的线程(优先级高的先被唤醒,否则随机)
- dispatch_semaphore_wait(semaphone, dispatch_time(DISPATCH_TIME_NOW, 5));
- 每运行一次,semaphone计数-1,如果semaphone计数为0,那么根据传入的等待时间等待,如果等待时间设置为DISPATCH_TIME_FOREVER,那么就永远等待,永远不会执行之后的了, 除非信号量计数>1了!
- (可以这么理解: 在这里判断是否有停车位剩余,如果有就停车,没有的话就等待车位空出再停车,如果超出等待时间,这个人就等不下去了,开车走了);
- 如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程自动执行其后语句
1 | // sample1: |
1 | // sample2: |
以上两种方案的话 看你情况使用!(信号量设为0 ,!0)
dispatch_group
dispatch_group_notify
监听dispatch_queue中所有的任务执行完成,执行某些操作1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, self.concurrentQueue, ^{
for (int i = 0; i < 3; i++) {
NSLog(@"1 %@ %zd", [NSThread currentThread], i);
}
});
NSLog(@"haha 1111");
dispatch_group_async(group, self.serialQueue, ^{
for (int i = 0; i < 3; i++) {
NSLog(@"2 %@ %zd", [NSThread currentThread], i);
}
});
NSLog(@"haha 2222");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 任务全部完成处理
NSLog(@"组内任务全部完成,请检验...");
});enter && levep
- dispatch_group_enter(group); 进入组
- dispatch_group_leave(group); 离开组
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);(等待组内任务完成)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 3; i++) {
dispatch_group_enter(group);
dispatch_async(self.concurrentQueue, ^{
NSLog(@"进入第%zd个异步 sleep 3秒", i);
sleep(3);
NSLog(@"离开第%zd个异步 sleep 完成", i);
dispatch_group_leave(group);
});
}
// 1 -----
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"网络下载任务全部完成,请刷新UI");
});
// // 2 ------ 1/2 任选1
// dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// NSLog(@"网络下载任务全部完成,请刷新UI");
// });