什么是GCD
GCD是苹果对多线程编程做的一套新的抽象基于C语言层的API,结合Block简化了多线程的操作,使得我们对线程操作能够更加的安全高效。
在GCD出现之前Cocoa框架提供了NSObject类的
performSelectorInBackground:withObject
performSelectorOnMainThread
方法来简化多线程编程技术。
GCD可以解决以下多线程编程中经常出现的问题:
1.数据竞争(比如同时更新一个内存地址)
2.死锁(互相等待)
3.太多线程导致消耗大量内存
在iOS中,如果把需要消耗大量时间的操作放在主线程上面,会妨碍主线程中被称为RunLoop的主循环的执行,从而导致不能更新用户界面、应用程序的画面长时间停滞等问题。
Dispatch Queue
Dispatch Queue是GCD中对于任务的抽象队列(FIFO)执行处理。
queue分为两种,
SERIAL_DISPATCH_QUEUE 等待现在执行中处理结束
CONCURRENT_DISPATCH_QUEUE 不等待现在执行中处理结束
换句话说也就是 SERIAL_DISPATCH_QUEUE 是串行,CONCURRENT_DISPATCH_QUEUE是并行。
具体到线程上,就是SERIAL_DISPATCH_QUEUE只会创在一个线程来处理任务序列,而CONCURRENT_DISPATCH_QUEUE则会创在多个线程,但是具体创建多少个则是有运行的操作系统根据资源决定的。
所以SERIAL_DISPATCH_QUEUE 中处理的代码是有序的,而CONCURRENT_DISPATCH_QUEUE中则是无序的,但是相对会更高效一点。
API
dispatch_queue_create
用于创建一个任务执行queue
参数列表
const char *label queue的名称,作为该queue的唯一标示,改名会在Xcode和Instruments的调试器中直接作为DispatchQueue名称显示出来
dispatch_queue_attr_t 设定queue的类型,即ConcurrentQueue还是SerialQueue,NULL则默认为SerialQueue
返回值
dispatch_queue_t变量
这里要说一下main_dispatch_queue 和 global_dispatch_queue 这两种系统提供的,
main_queue通过
dispatch_get_main_queue()
global_queue通过
dispatch_get_global_queue(),global等级分为
HIGH、DEFAULT、LOW、BACKGROUND四种
dispatch_after
类似延迟函数,可以指定queue来进行延迟操作
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC); dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"等待3秒"); });
dispatch_group_notify
对于监听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(@"1"); }); dispatch_group_async(group, queue, ^{ NSLog(@"2"); }); dispatch_group_async(group, queue, ^{ NSLog(@"3"); }); dispatch_group_notify(group, queue, ^{ NSLog(@"finish"); });
对于一系列的block在同一queue中执行,如果是serialQueue是顺序进行的,因此可以在最后一个任务来处理结束操作。但是对于concurrentQueue是并行的,如果想监听完结操作,就要用该方法。
dispatch_group_wait和notify差不多,只不过wait方法可以设置等待时间。如果时间到了还没有结束queue的所有操作,那么接下来还是会继续进行,不过还是可以设定为forever一直等待下去,这样就和notify起到一样的作用。
dispatch_barrier_async
该操作主要是为了防止资源竞争。在concurrentQueue中,所有block无序的按照所创建的线程数量同时进行。如果在concurrentQueue中有两个写入操作,而且他都是读取操作,这时两个写入操作间就会出现资源竞争,而读取操作则会读取脏数据。所以对于在concurrentQueue中不能够与其它操作并行的block就需要使用dispatch_barrier_async方法来防止资源竞争。