Dispatch Queue
Serial Dispatch Queue
:依次执行,等待现在执行中处理结束Concurrent Dispatch Queue
: 并发执行,不等待现在执行中处理结束
Dispatch Queue 种类
1 | // serial dispatch queue |
dispatch_set_target_queue
dispatch_queue_create
生成的队列都是具有默认有优先级,因此变更队列的优先级使用dispatch_set_target_queue
。将不可并行执行的处理追加到多个Serial Dispatch Queue
中时,如果使用dispatch_set_target_queue
函数指定为某一个Serial Dispatch Queue
,则可以防止处理并行执行。
注意:
第一个参数如果指定为Main Dispatch Queue
和Global Dispatch Queue
则不知道会出现什么情况,因此这些均不可指定。
1 | dispatch_queue_t serialDispatchQueue = dispatch_queue_create("com.serial", NULL); |
dispatch_after
使用dispatch_after
延时将Block追加到Main Dispatch Queue
中处理。
1 | dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC); |
Dispatch Group
在追加多个Dispatch Queue中的多个处理全部结束后想执行结束处理,使用Dispatch Group。
1 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
dispatch_barrier_async
使用dispatch_barrier_async
来避免读写数据库导致的竞争。使用Concurrent Dispatch Queue
和dispatch_barrier_async
可以实现高效率的数据库访问和文件访问。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15dispatch_queue_t queue = dispatch_queue_create("com.gcd.concureent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{NSLog(@"blk0_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk1_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk2_for_reading");});
dispatch_barrier_async(queue, ^{NSLog(@"blk2_for_writing");});
dispatch_async(queue, ^{NSLog(@"blk3_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk4_for_reading");});
// output
// blk0_for_reading
// blk1_for_reading
// blk2_for_reading
// blk2_for_writing
// blk3_for_reading
// blk4_for_reading
dispatch_sync、dispatch_async
dispatch_async:
将指定Block非同步
追加到指定的Dispatch Queue中,dispatch_async函数不等待Block内的处理结束。dispatch_sync:
将指定Block同步
追加到指定的Dispatch Queue中,在追加Block结束之前,dispatch_sync函数会一直等待Block内部的处理结束。
在Main Dispatch Queue
中谨慎使用dispatch_sync
,这样会造成死锁:
Main Dispatch Queue
等待Block执行结束,而主线程正在执行这些代码,dispatch_sync
又在等待主队列任务结束才将Block添加进queue,所以无法将Block追加到Main Dispatch Queue
当中,最终造成死锁。1
2dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{ NSLog(@"Hello!"); });
同行以下也会造成死锁:
1 | dispatch_queue_t queue = dispatch_get_main_queue(); |
1 | dispatch_queue_t queue = dispatch_queue_create("com.serialQueue", NULL); |
dispatch_apply
dispatch_apply
是dispatch_sync
和Dispatch Group
的关联API,该函数指定的次数将指定的Block追加到指定的Dispatch Queue
中,并等待全部处理执行结束。
注意:
由于dispatch_apply
和dispatch_sync
相同,会等待处理执行结束,因此推荐在dispatch_async
函数中非同步地执行dispatch_apply
:
1 | NSArray *array = @[@0, @1, @2, @3, @4]; |
dispatch_suspend/dispatch_resume
dispatch_suspend(queue)
:挂起指定的 queuedispatch_resume(queue)
:恢复指定的 queue
Disptach Semaphore
提供比 Serial Dispatch Queue
和 dispatch_barrier_async
更加细粒度的控制:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 生成 Dispatch Semaphore,并将计数器初始值设定为 1
// 保证可访问 NSMutableArray 类对象的线程同时只能有1个
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < 10000; ++i) {
dispatch_async(queue, ^{
// 等待 Dispatch Semaphore,一直等待,直到 Dispatch Semaphore 的计数值达到大于等于 1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// Dispatch Semaphore 的计数器大于等于 1,所以将 Dispatch Semaphore 的计数器减去 1,dispatch_semaphore_wait 函数执行返回
// 由于可访问 NSMutableArray 类对象的线程只有 1 个,因此可安全地进行更新
[array addObject:[NSNumber numberWithInt:i]];
// 排他控制结束,所以通过 dispatch_semaphore_signal 函数,将 Dispatch Semaphore 的计数器加 1
// 如果有通过 dispatch_semaphore_wait 函数,等待Dispatch Semaphore的计数值增加的线程,就由最先等待的线程执行
dispatch_semaphore_signal(semaphore);
});
}
dispatch_once
dispatch_once
能够在使用多线程环境下,也可保证百分之百安全,这就是单例模式
。1
2
3
4static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// ...
});
Dispatch I/O
如果想要提高文件读取速度,可以使用 Dispatch I/O
dispatch_io_read
:使用 Global Dispatch Queue
开始并列读取。dispatch_io_set_low_water
:设定第一次读取的大小(分割大小)。