GCD基础部分
注:本节主要详细讲解线程同步的一些基本概念和GCD基础部分
GCD (Grand Central Dispatch)
首先我们来了解处理线程中的一些基本概念 :
串行:同时只能有一个任务被执行
并发:同时可以有多个任务执行
同步:同步任务会阻塞当前线程,知道任务完成
死锁:多个线程卡住了 , 并等待对方完成或执行其它操作。第一个不能完成是因为它在等待第二个的完成。但第二个也不能完成,因为它在等待第一个的完成。
上下文切换:一个上下文切换指当你在单个进程里切换执行不同的
线程时存储与恢复执行状态的过程。这个过程在编写多任务应用时很普遍,但会带来一些额外的开销并发与并行:并发代码的不同部分可以“同步”执行。多核设备通过并行来同时执行多个线程;为了使单核设备也能实现这一点,它们必须先运行一个线程,执行一个上下文切换,然后运行另一个线程或进程。这通常发生地足够快以致给我们并发执行地错觉
Queues 队列:GCD 提供有 dispatch queues 来处理代码块,这些队列管理你提供给 GCD 的任务并用 FIFO(先进先出) 顺序执行这些任务。所有的调度队列(dispatch queues)自身都是线程安全的,你能从多个线程并行的访问它们。当你了解了调度队列如何为你自己代码的不同部分提供线程安全后,GCD的优点就是显而易见的。关于这一点的关键是选择正确类型的调度队列和正确的调度函数来提交你的工作。由于在串行队列中不会有两个任务并发运行,因此不会出现同时访问临界区的风险;相对于这些任务来说,这就从竞态条件下保护了临界区。所以如果访问临界区的唯一方式是通过提交到调度队列的任务,那么你就不需要担心临界区的安全问题了。
Concurrent Queues 并发队列:在并发队列中的任务能得到的保证是它们会按照被添加的顺序开始执行,但这就是全部的保证了。任务可能以任意顺序完成,你不会知道何时开始运行下一个任务,或者任意时刻有多少 Block 在运行。这完全取决于 GCD 。
如果一个 Block 的执行时间与另一个重叠,也是由 GCD 来决定是否将其运行在另一个不同的核心上,如果那个核心可用,否则就用上下文切换的方式来执行不同的 Block 。Queue Types 队列类型:首先,系统提供给你一个叫做 主队列(main queue) 的特殊队列。和其它串行队列一样,这个队列中的任务一次只能执行一个。然而,它能保证所有的任务都在主线程执行,而主线程是唯一可用于更新 UI 的线程。这个队列就是用于发生消息给 UIView 或发送通知的。
系统同时提供给你好几个并发队列。它们叫做 全局调度队列(Global Dispatch Queues) 。目前的四个全局队列有着不同的优先级:background、low、default 以及 high。要知道,Apple 的 API 也会使用这些队列,所以你添加的任何任务都不会是这些队列中唯一的任务。
最后,你也可以创建自己的串行队列或并发队列。这就是说,至少有五个队列任你处置:主队列、四个全局调度队列,再加上任何你自己创建的队列。GCD 的“艺术”归结为选择合适的队列来调度函数以提交你的工作。
下面看下示例
Global Dispatch Queues
let back = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
let defual = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
let high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
let low = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);
dispatch_async(back) {
//后台执行
}
dispatch_async(defual) {
//后台执行
}
dispatch_async(low) {
//后台执行
}
dispatch_async(high) {
//后台执行
}
上面是全局后台执行的几种类型。可以设定级别
下面看看主线程。多用来刷新UI
dispatch_async(dispatch_get_main_queue()) {
//主线程执行
}
用户队列
let queue = dispatch_queue_create("myQueue",nil);
dispatch_async(queue) {
//后台执行
}
下面是延时执行
let time = NSEC_PER_SEC*3
let popTime = dispatch_time(DISPATCH_TIME_NOW,Int64(time))
print(NSEC_PER_SEC)
dispatch_after(popTime,dispatch_get_main_queue()) {
//这里的内容在3秒后执行
print(2)
}
print(1)
这里NSEC_PER_SEC = 1000000000
先输出1 三秒后输出2
dispatch_once 在单例模式中很有用哦 , 不用if判断。加上这个就能保证 只执行一次了
func onlyOnce(){
struct Static {
static var onceToken : dispatch_once_t = 0
}
dispatch_once(&Static.onceToken) {
print("只会输出一次哦")
}
print("多次输出呀")
}
这里static变量保证用的是同一个token
onlyOnce()
onlyOnce()
onlyOnce()
onlyOnce()
onlyOnce()
然后我们多次调用 。
只会输出一次哦 多次输出呀 多次输出呀 多次输出呀 多次输出呀 多次输出呀
dispatch_once中的代码只执行了一次 。
以上就是今天总结的GCD基础部分 。下次总结下高级部分