花了一天时间,看了Objective-C高级编程(iOS与OS X多线程和内存管理),对GCD有了初步的认识,大致有下面一些概念。
Dispatch Queue
分两类:Serial Dispatch Queue,Concurrent Dispatch Queue。Serial Dispatch Queue使用一个线程执行多个处理。Concurrent Dispatch Queue使用多个线程执行多个处理。
Dispatch_after
延迟执行处理
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ULL * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"waited at least three seconds");
})
需要注意的是:dispatch_after并不是在指定时间后执行处理,而是在指定时间追加处理到Dispatch Queue中。
因为Main Dispatch Queue在主线程的RunLoop中执行,所以在比如每隔1/60秒执行的RunLoop中,Block最快3秒后执行,最慢在3秒+1/60秒后执行。
扩展:dispatch_time(...)与dispatch_walltime(...)的区别,dispatch_time(...)通常用于计算相对时间,dispatch_walltime(...)计算绝对时间。
Dispatch Group
在追加到Dispatch Queue中的多个处理全部结束后执行结束处理。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk0")});
dispatch_group_async(group, queue, ^{NSLog(@"blk1")});
dispatch_group_async(group, queue, ^{NSLog(@"blk2")});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done")});
dispatch_release(group);
无论向什么样的Dispatch Queue中添加处理,使用Dispatch Group都可监视这些处理执行的结束,一旦检测到所有处理执行结束,就可将结束的处理追加到Dispatch Queue中,这就是使用Dispatch Group的原因。
dispatch_barrier_async
在访问数据库或文件时,使用Concurrent Dispatch Queue会发生数据竞争,导致读取到与期待不符的数据,还可能因非法访问导致应用程序异常结束。 dispatch_barrier_async和Concurrent Dispatch Queue配合使用可实现高效率的数据库访问和文件访问。
dispatch_barrier_async函数会等待追加到Concurrent Dispatch Queue上的并行执行的处理全部结束后,再将指定的处理追加到该Concurrent Dispatch Queue中,然后再由dispatch_barrier_async函数追加的处理执行完毕后,Concurrent Dispatch Queue才恢复为一般的动作,追加到该Concurrent Dispatch Queue的处理又开始并行执行。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk0_for_reading);
dispatch_barrier_async(queue, blk0_for_writing);
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk0_for_reading);
dispatch_sync
将指定的block处理“同步”追加到指定的Dispatch Queue中,在追加Block结束之前,dispatch_sync函数会一直等待,即当前线程停止。
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{NSLog(@"Hello?");});
以上源码会导致死锁
dispatch_apply
dispatch_apply函数是dispatch_sync和Dispatch Group的关联API,该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(5, queue, ^(size_t index){NSLog(@"%zu", index);});
NSLog(@"done");
第一个参数为重复次数。第三个参数的Block为带有参数的Block,这是为了按第一个参数重复添加Block并区分各个Block耳使用的。
dispatch_suspend / dispatch_resume
挂起Dispatch Queue / 恢复Dispatch Queue
这些函数对已经执行的处理没有影响,挂起后,追加到Dispatch Queue中但尚未执行的处理在此之后停止执行。而恢复则使得这些处理能够继续执行。
Dispatch Semaphore
持有计数的信号,计数为0时等待,计数为1或大于1时,减去1而不等待。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < 1000; i ++) {
dispatch_aync(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[array addObject:@(i)];
dispatch_semaphore_signal(semaphore);
})
}
dispatch_release(semaphore);
dispatch_once
dispatch_once函数是保证在应用程序执行中只执行一次指定处理的API。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{/*初始化*/});
Dispatch I/O
多线程并发分块读取大文件。