GCD 简介
Grand Central Dispatch
一 任务与队列
1 任务
所需要执行的操作
同步(sync)
- 不具备开辟新线程的能力
- 等待队列里的任务完成之后在执行
异步(async)
- 不会做任何等待,可以继续执行任务
- 具备开辟新线程的能力
2 队列
这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则。
并发队列(Concurrent Dispatch Queue)
- 可开辟多条线程,可以同时执行多个任务。
串行队列 (Serial Dispatch Queue)
- 只有一条线程,任务一个接着一个地执行,每次只执行一个任务。
二 创建任务与队列
1 任务
- 同步
queue.sync {
}
- 异步
queue.async {
}
2 队列
- 串行队列
//获取主队列(特殊的串行队列)
let queue = DispatchQueue.main
//创建串行队列
let queue = DispatchQueue(label: "--")
let queue = DispatchQueue(label: "--", qos: .default, attributes: .init(), autoreleaseFrequency: .inherit, target: nil)
- 并行队列
//获取全局并发队列
let queue = DispatchQueue.global()
let queue = DispatchQueue.global(qos: .default)
//创建并发队列
let queue = DispatchQueue(label: "--", qos: .userInteractive, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
三 任务与队列的组合
1 同步执行 + 并发队列
- 没有开辟新线程,所有的任务都是在当前线程(主线程)上执行的(同步执行无法开辟新线程)。
- 任务都是按照顺序执行,执行一个在执行下一个。
func testGCD() {
let queue = DispatchQueue.global()
print("begin=\(Thread.current)")
queue.sync {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 1)
print("3=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 3)
print("4=====\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x6000007b01c0>{number = 1, name = main}
1=====<NSThread: 0x6000007b01c0>{number = 1, name = main}
2=====<NSThread: 0x6000007b01c0>{number = 1, name = main}
3=====<NSThread: 0x6000007b01c0>{number = 1, name = main}
4=====<NSThread: 0x6000007b01c0>{number = 1, name = main}
end===<NSThread: 0x6000007b01c0>{number = 1, name = main}
2 同步执行 + 串行队列
- 没有开辟新线程,所有的任务都是在当前线程(主线程)上执行的(同步执行无法开辟新线程)。
- 任务都是按照顺序执行,执行一个在执行下一个。
func testGCD() {
let queue = DispatchQueue(label: "Test")
print("begin=\(Thread.current)")
queue.sync {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 1)
print("3=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 3)
print("4=====\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x6000012703c0>{number = 1, name = main}
1=====<NSThread: 0x6000012703c0>{number = 1, name = main}
2=====<NSThread: 0x6000012703c0>{number = 1, name = main}
3=====<NSThread: 0x6000012703c0>{number = 1, name = main}
4=====<NSThread: 0x6000012703c0>{number = 1, name = main}
end===<NSThread: 0x6000012703c0>{number = 1, name = main}
3 同步执行 + 主队列
- 相互阻塞卡死
- testGCD在主线程上执行,任务1-4也在主线程上执行,testGCD等待任务执行,任务等待testGCD执行,相互等待卡死线程。
func testGCD() {
let queue = DispatchQueue.main
print("begin=\(Thread.current)")
queue.sync {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 1)
print("3=====\(Thread.current)")
}
queue.sync {
Thread.sleep(forTimeInterval: 3)
print("4=====\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x600002920900>{number = 1, name = main}
(lldb)
4 同步执行 + 主队列(其他线程)
- 所有任务在主线程中执行,非当前线程,任务按照顺序执行。
- testGCD不在主线程上执行,与任务不在同一线程,不会卡住。
Thread.detachNewThread {
self.testGCD()
}
//结果
begin=<NSThread: 0x600003b1e480>{number = 6, name = (null)}
1=====<NSThread: 0x600003b741c0>{number = 1, name = main}
2=====<NSThread: 0x600003b741c0>{number = 1, name = main}
3=====<NSThread: 0x600003b741c0>{number = 1, name = main}
4=====<NSThread: 0x600003b741c0>{number = 1, name = main}
end===<NSThread: 0x600003b1e480>{number = 6, name = (null)}
5 异步执行 + 串行队列
- 创建一个新线程
- 异步执行不做任何等待。
- 串行队列任务按照顺序执行。
func testGCD() {
let queue = DispatchQueue(label: "Test")
print("begin=\(Thread.current)")
queue.async {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 1)
print("3=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 3)
print("4=====\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x6000008b01c0>{number = 1, name = main}
end===<NSThread: 0x6000008b01c0>{number = 1, name = main}
1=====<NSThread: 0x6000008a27c0>{number = 4, name = (null)}
2=====<NSThread: 0x6000008a27c0>{number = 4, name = (null)}
3=====<NSThread: 0x6000008a27c0>{number = 4, name = (null)}
4=====<NSThread: 0x6000008a27c0>{number = 4, name = (null)}
6 异步执行 + 并发队列
- 会开辟多条新线程。
- 任务交替执行不做任何等待。
func testGCD() {
let queue = DispatchQueue.global()
print("begin=\(Thread.current)")
queue.async {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 1)
print("3=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 3)
print("4=====\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x600001f84280>{number = 1, name = main}
end===<NSThread: 0x600001f84280>{number = 1, name = main}
3=====<NSThread: 0x600001fdde80>{number = 3, name = (null)}
4=====<NSThread: 0x600001fe0940>{number = 7, name = (null)}
1=====<NSThread: 0x600001f887c0>{number = 4, name = (null)}
2=====<NSThread: 0x600001f88d80>{number = 5, name = (null)}
7 异步执行 + 主队列
- 在主线程中执行,没有开辟新线程,在主队列中放入主线程中执行。
- 异步执行不做任何等待。
- 任务按顺序执行,因为主线程是串行队列。
func testGCD() {
let queue = DispatchQueue.main
print("begin=\(Thread.current)")
queue.async {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 1)
print("3=====\(Thread.current)")
}
queue.async {
Thread.sleep(forTimeInterval: 3)
print("4=====\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x6000013b83c0>{number = 1, name = main}
end===<NSThread: 0x6000013b83c0>{number = 1, name = main}
1=====<NSThread: 0x6000013b83c0>{number = 1, name = main}
2=====<NSThread: 0x6000013b83c0>{number = 1, name = main}
3=====<NSThread: 0x6000013b83c0>{number = 1, name = main}
4=====<NSThread: 0x6000013b83c0>{number = 1, name = main}
四 线程间的通讯
- 主线程刷新应用
func testGCD() {
let queue = DispatchQueue.global()
print("begin=\(Thread.current)")
queue.async {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
DispatchQueue.main.async {
print("2=====\(Thread.current)")
}
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x600000a081c0>{number = 1, name = main}
end===<NSThread: 0x600000a081c0>{number = 1, name = main}
1=====<NSThread: 0x600000a55000>{number = 6, name = (null)}
2=====<NSThread: 0x600000a081c0>{number = 1, name = main}
五 其他应用方式
1 队列组:dispatch_group
- group.notify 同时执行多个异步耗时请求,最终回到主线程。
func testGCD() {
let queue = DispatchQueue(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
let group = DispatchGroup()
print("begin=\(Thread.current)")
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 5)
print("3=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("4=====\(Thread.current)")
}
group.notify(queue: DispatchQueue.main) {
print("notify\(Thread.current)")
}
print("end===\(Thread.current)")
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("5=====\(Thread.current)")
}
}
//结果
begin=<NSThread: 0x60000033c1c0>{number = 1, name = main}
end===<NSThread: 0x60000033c1c0>{number = 1, name = main}
3=====<NSThread: 0x60000037c280>{number = 5, name = (null)}
1=====<NSThread: 0x600000366840>{number = 7, name = (null)}
5=====<NSThread: 0x60000037c140>{number = 3, name = (null)}
2=====<NSThread: 0x600000366a80>{number = 6, name = (null)}
4=====<NSThread: 0x60000032a3c0>{number = 9, name = (null)}
notify<NSThread: 0x60000033c1c0>{number = 1, name = main}
- group.enter() 未执行任务+1, group.leave() 未执行任务-1, 未执行任务=0,才会解除阻塞,继续执行后续代码。
func testGCD() {
let queue = DispatchQueue(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
let group = DispatchGroup()
print("begin=\(Thread.current)")
group.enter()
queue.async {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
group.leave()
}
group.enter()
queue.async {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
group.leave()
}
group.enter()
queue.async {
Thread.sleep(forTimeInterval: 5)
print("3=====\(Thread.current)")
group.leave()
}
group.notify(queue: DispatchQueue.main) {
print("notify\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x6000036e0a40>{number = 1, name = main}
end===<NSThread: 0x6000036e0a40>{number = 1, name = main}
3=====<NSThread: 0x6000036a1bc0>{number = 5, name = (null)}
1=====<NSThread: 0x600003688040>{number = 3, name = (null)}
2=====<NSThread: 0x6000036be100>{number = 4, name = (null)}
notify<NSThread: 0x6000036e0a40>{number = 1, name = main}
- group.wait() 阻塞当前线程,暂停当前线程。wait后面所有代码都不执行。
func testGCD() {
let queue = DispatchQueue(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
let group = DispatchGroup()
print("begin=\(Thread.current)")
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 5)
print("3=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("4=====\(Thread.current)")
}
group.wait()
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("5=====\(Thread.current)")
}
group.notify(queue: DispatchQueue.main) {
print("notify\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x600000484900>{number = 1, name = main}
3=====<NSThread: 0x6000004ddec0>{number = 7, name = (null)}
1=====<NSThread: 0x6000004e4040>{number = 6, name = (null)}
4=====<NSThread: 0x6000004d4700>{number = 8, name = (null)}
2=====<NSThread: 0x6000004cb500>{number = 5, name = (null)}
end===<NSThread: 0x600000484900>{number = 1, name = main}
5=====<NSThread: 0x6000004cb500>{number = 5, name = (null)}
notify<NSThread: 0x600000484900>{number = 1, name = main}
- group.barrier 不会阻塞线程,group中barrier后的代码后执行。
func testGCD() {
let queue = DispatchQueue(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
let group = DispatchGroup()
print("begin=\(Thread.current)")
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 5)
print("1=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("2=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 5)
print("3=====\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .barrier) {
print("barrier==\(Thread.current)")
}
queue.async(group: group, qos: .default, flags: .inheritQoS) {
Thread.sleep(forTimeInterval: 7)
print("4=====\(Thread.current)")
}
group.notify(queue: DispatchQueue.main) {
print("notify\(Thread.current)")
}
print("end===\(Thread.current)")
}
//结果
begin=<NSThread: 0x6000038c83c0>{number = 1, name = main}
end===<NSThread: 0x6000038c83c0>{number = 1, name = main}
3=====<NSThread: 0x6000038c00c0>{number = 8, name = (null)}
1=====<NSThread: 0x600003880ec0>{number = 6, name = (null)}
2=====<NSThread: 0x600003894400>{number = 5, name = (null)}
barrier==<NSThread: 0x600003894400>{number = 5, name = (null)}
4=====<NSThread: 0x600003894400>{number = 5, name = (null)}
notify<NSThread: 0x6000038c83c0>{number = 1, name = main}
2 延时执行
- 延迟执行任务
queue.asyncAfter(deadline: .now() + 3) {
print("after=\(Thread.current)")
}
3 信号量
- 保持线程同步
- 保证线程安全
func testGCD() {
let queue = DispatchQueue.global()
//创建一个 Semaphore 并初始化信号的总量
let semaphore = DispatchSemaphore(value: 0)
print("begin====\(Thread.current)")
queue.async {
Thread.sleep(forTimeInterval: 5)
print("signal===\(Thread.current)")
//发送一个信号,让信号总量加 1
semaphore.signal()
}
//可以使总信号量减 1,信号总量小于 0 时就会一直等待(阻塞所在线程),否则就可以正常执行。
semaphore.wait()
print("end======\(Thread.current)")
}
//结果
begin====<NSThread: 0x600001970a40>{number = 1, name = main}
signal===<NSThread: 0x6000019342c0>{number = 7, name = (null)}
end======<NSThread: 0x600001970a40>{number = 1, name = main}
- 线程加锁
func initMoney() {
semaphore = DispatchSemaphore(value: 1)
money = 10
let queueOne = DispatchQueue(label: "queueOne")
let queueTwo = DispatchQueue(label: "queueTwo")
let queueThree = DispatchQueue(label: "queueThree")
queueOne.async {
self.takeMoney()
}
queueTwo.async {
self.takeMoney()
}
queueThree.async {
self.takeMoney()
}
}
func takeMoney() {
while (1 != 0) {
semaphore.wait()
if money > 0 {
money = money - 1
print("money==\(String(describing: money))==\(Thread.current)")
} else {
print("no money====\(Thread.current)")
semaphore.signal()
break
}
semaphore.signal()
}
}
//结果
money==Optional(9)==<NSThread: 0x6000023a4fc0>{number = 7, name = (null)}
money==Optional(8)==<NSThread: 0x6000023f5d80>{number = 6, name = (null)}
money==Optional(7)==<NSThread: 0x600002390900>{number = 5, name = (null)}
money==Optional(6)==<NSThread: 0x6000023a4fc0>{number = 7, name = (null)}
money==Optional(5)==<NSThread: 0x6000023f5d80>{number = 6, name = (null)}
money==Optional(4)==<NSThread: 0x600002390900>{number = 5, name = (null)}
money==Optional(3)==<NSThread: 0x6000023a4fc0>{number = 7, name = (null)}
money==Optional(2)==<NSThread: 0x6000023f5d80>{number = 6, name = (null)}
money==Optional(1)==<NSThread: 0x600002390900>{number = 5, name = (null)}
money==Optional(0)==<NSThread: 0x6000023a4fc0>{number = 7, name = (null)}
no money====<NSThread: 0x6000023f5d80>{number = 6, name = (null)}
no money====<NSThread: 0x600002390900>{number = 5, name = (null)}
no money====<NSThread: 0x6000023a4fc0>{number = 7, name = (null)}