GCD
GCD即Grand Central Dispatch, 是苹果推荐使用的多线程技术, 它可以充分利用多核.它通过队列来安排任务, GCD队列分为三种:
- 全局队列
- 主队列
- 串行队列
下面我们学习它们
1. 全局队列
全局队列是一个并发队列. 我们来创建一个全局队列:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
第一个参数:DISPATCH_QUEUE_PRIORITY_HIGH,DISPATCH_QUEUE_PRIORITY_DEFAULT,DISPATCH_QUEUE_PRIORITY_LOW,DISPATCH_QUEUE_PRIORITY_BACKGROUND中的一个,它指定优先级, 一般用DISPATCH_QUEUE_PRIORITY_DEFAULT即可
第二个参数: 苹果留着的以后扩展用的, 传0即可, 传其它值可能会返回空
2. 串行队列
串行就是一个接一个的执行,只会开一个线程.串行队列要自己创建:
let queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)
第一个参数: 队列名字, 随意取
第二个参数: 队列类型, 可以是DISPATCH_QUEUE_SERIAL(串行队列),DISPATCH_QUEUE_CONCURRENT(并行队列)
3. 主队列
它是一个特殊的串行队列, 它的任务都在主线程中运行,程序运行,主线程就已经运行,而主队列也就已经存在, 我可以直接获取:
let queue = dispatch_get_main_queue()
4. GCD的任务派遣方式
GCD的任务派遣方式有两种: dispatch_async 和 dispatch_sync
现在我们实现一个例子, 对上面的三种队列,我们分别使用同步和异步的派遣方式,来观察线程的开启情况:
import UIKit
class ViewController: UIViewController {
var mainQueue: dispatch_queue_t!
var globalQueue: dispatch_queue_t!
var serialQueue: dispatch_queue_t!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// 全局队列
globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
// 串行队列
serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)
// 主队列
mainQueue = dispatch_get_main_queue()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func globalQueueAsyncAction(sender: AnyObject) {
dispatch_async(globalQueue) { () -> Void in
print("全局队列_异步派遣: \(NSThread.currentThread())")
}
}
@IBAction func globalQueueSyncAction(sender: AnyObject) {
dispatch_sync(globalQueue) { () -> Void in
print("全局队列_同步派遣: \(NSThread.currentThread())")
}
}
@IBAction func serialQueueAsyncAction(sender: AnyObject) {
dispatch_async(serialQueue) { () -> Void in
print("串行队列_异步派遣: \(NSThread.currentThread())")
}
}
@IBAction func serialQueueSyncAction(sender: AnyObject) {
dispatch_sync(serialQueue) { () -> Void in
print("串行队列_同步派遣: \(NSThread.currentThread())")
}
}
@IBAction func mainQueueAsyncAction(sender: AnyObject) {
dispatch_async(mainQueue) { () -> Void in
print("主队列_异步派遣: \(NSThread.currentThread())")
}
}
@IBAction func mainQueueSyncAction(sender: AnyObject) {
dispatch_sync(mainQueue) { () -> Void in
print("主队列_同步派遣: \(NSThread.currentThread())")
}
}
}
然后我们查看不同的情况的打印的值,每个按钮点上3遍:
全局队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 2, name = (null)}
全局队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 2, name = (null)}
全局队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 2, name = (null)}
我们可以看出: globalQueue和dispatch_async的组合会开启新的线程
全局队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
全局队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
全局队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
我们可以看出: globalQueue和dispatch_sync的组合不会开启新的线程,就在主线程中运行
串行队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 3, name = (null)}
串行队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 3, name = (null)}
串行队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 3, name = (null)}
我们可以看出: serialQueue和dispatch_async的组合会开启新的线程
串行队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
串行队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
串行队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
我们可以看出: serialQueue和dispatch_sync的组合不会开启新的线程,就在主线程中运行
主队列_异步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
主队列_异步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
主队列_异步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
我们可以看出: mainQueue和dispatch_async的组合不会开启新的线程,就在主线程中运行
主队列_同步派遣即mainQueue和dispatch_sync的组合, 模拟器直接卡死了.
现在我们可以总结一下了:
globalQueue serialQueue mainQueue
dispatch_async 开新线程运行 开新线程运行 主线程运行
dispatch_sync 主线程运行 主线程运行 模拟器卡死
一般的情况:
执行耗时操作, dispatch_async + globalQueue, 然后耗时操作完成, 更新UI的时候dispatch_async + mainQueue
5. GCD的组操作
当要监听一系列任务都执行完成时,如下载多个音乐完成后,我们要给个提示,这就要使用GCD的组了.
我们在storyboard中拖拽一个按钮,添加监听方法:
@IBAction func groupAction(sender: AnyObject) {
let group = dispatch_group_create()
dispatch_group_async(group, globalQueue) { () -> Void in
print("下载音乐1, \(NSThread.currentThread())")
}
dispatch_group_async(group, globalQueue) { () -> Void in
print("下载音乐2, \(NSThread.currentThread())")
}
dispatch_group_async(group, globalQueue) { () -> Void in
print("下载音乐3, \(NSThread.currentThread())")
}
dispatch_group_notify(group, globalQueue) { () -> Void in
print("下载完成")
}
}
运行程序, 点击按钮:
下载音乐2, <NSThread: 0x7f966bf38ee0>{number = 3, name = (null)}
下载音乐1, <NSThread: 0x7f966bc28ae0>{number = 2, name = (null)}
下载音乐3, <NSThread: 0x7f966bd28190>{number = 4, name = (null)}
下载完成
可以发现, 异步任务的顺序是不确定的, 但是使用群组可以在所有任务执行完成后执行一个block.
6. 完整代码
import UIKit
class ViewController: UIViewController {
var mainQueue: dispatch_queue_t!
var globalQueue: dispatch_queue_t!
var serialQueue: dispatch_queue_t!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// 全局队列
globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
// 串行队列
serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)
// 主队列
mainQueue = dispatch_get_main_queue()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func globalQueueAsyncAction(sender: AnyObject) {
// 开启新的线程
dispatch_async(globalQueue) { () -> Void in
print("全局队列_异步派遣: \(NSThread.currentThread())")
}
}
@IBAction func globalQueueSyncAction(sender: AnyObject) {
// 运行在主线程
dispatch_sync(globalQueue) { () -> Void in
print("全局队列_同步派遣: \(NSThread.currentThread())")
}
}
@IBAction func serialQueueAsyncAction(sender: AnyObject) {
dispatch_async(serialQueue) { () -> Void in
print("串行队列_异步派遣: \(NSThread.currentThread())")
}
}
@IBAction func serialQueueSyncAction(sender: AnyObject) {
dispatch_sync(serialQueue) { () -> Void in
print("串行队列_同步派遣: \(NSThread.currentThread())")
}
}
@IBAction func mainQueueAsyncAction(sender: AnyObject) {
dispatch_async(mainQueue) { () -> Void in
print("主队列_异步派遣: \(NSThread.currentThread())")
}
}
@IBAction func mainQueueSyncAction(sender: AnyObject) {
dispatch_sync(mainQueue) { () -> Void in
print("主队列_同步派遣: \(NSThread.currentThread())")
}
}
@IBAction func groupAction(sender: AnyObject) {
let group = dispatch_group_create()
dispatch_group_async(group, globalQueue) { () -> Void in
print("下载音乐1, \(NSThread.currentThread())")
}
dispatch_group_async(group, globalQueue) { () -> Void in
print("下载音乐2, \(NSThread.currentThread())")
}
dispatch_group_async(group, globalQueue) { () -> Void in
print("下载音乐3, \(NSThread.currentThread())")
}
dispatch_group_notify(group, globalQueue) { () -> Void in
print("下载完成")
}
}
}