iOS GCD
任务和队列的创建方法 / 获取方法
队列的创建方法 / 获取方法
串行队列的创建方法
let serialQueue = DispatchQueue(label: "com.mouos.serial.queue")
并发队列的创建方法。并发队列 可开启多个线程,同时执行多个任务,队列的并发功能只有在异步(async)方法下才有效。
let concurrentQueue = DispatchQueue(label: "com.mouos.concurrent.queue", attributes: .concurrent)
主队列:GCD 默认提供的串行队列。
let mainQueue = DispatchQueue.main
全局并发队列的获取方法
let globalConcurrentQueue = DispatchQueue.global()
任务的创建方法
同步执行任务创建方法。同步执行不具备开启新线程的能力。
queue.sync {
}
异步执行任务创建方法。异步执行具备开启新线程的能力。
queue.async {
}
任务和队列不同组合方式
同步 + 并发
在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
let concurrentQueue = DispatchQueue(label: "com.mouos.concurrent.queue", attributes: .concurrent)
print("begin")
concurrentQueue.sync {
Thread.sleep(forTimeInterval: 3)
print("1")
}
concurrentQueue.sync {
Thread.sleep(forTimeInterval: 1)
print("2")
}
concurrentQueue.sync {
Thread.sleep(forTimeInterval: 2)
print("3")
}
print("end")
输出结果:
begin
1
2
3
end
同步 + 串行
不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。
let serialQueue = DispatchQueue(label: "com.mouos.serial.queue")
print("begin")
serialQueue.sync {
Thread.sleep(forTimeInterval: 3)
print("1")
}
serialQueue.sync {
Thread.sleep(forTimeInterval: 1)
print("2")
}
serialQueue.sync {
Thread.sleep(forTimeInterval: 2)
print("3")
}
print("end")
输出结果:
begin
1
2
3
end
异步 + 并发
可以开启多个线程,任务交替(同时)执行。
let concurrentQueue = DispatchQueue(label: "com.mouos.concurrent.queue", attributes: .concurrent)
print("begin")
concurrentQueue.async {
Thread.sleep(forTimeInterval: 3)
print("1")
}
concurrentQueue.async {
Thread.sleep(forTimeInterval: 1)
print("2")
}
concurrentQueue.async {
Thread.sleep(forTimeInterval: 2)
print("3")
}
print("end")
输出结果:
begin
end
2
3
1
异步 + 串行
会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务。
let serialQueue = DispatchQueue(label: "com.mouos.serial.queue")
print("begin")
serialQueue.async {
Thread.sleep(forTimeInterval: 3)
print("1")
}
serialQueue.async {
Thread.sleep(forTimeInterval: 1)
print("2")
}
serialQueue.async {
Thread.sleep(forTimeInterval: 2)
print("3")
}
print("end")
输出结果:
begin
end
1
2
3
线程间的通信
let mainQueue = DispatchQueue.main
let globalConcurrentQueue = DispatchQueue.global()
globalConcurrentQueue.async {
Thread.sleep(forTimeInterval: 2)
print("global - 耗时操作")
mainQueue.async {
Thread.sleep(forTimeInterval: 2)
print("main - 完成耗时操作,回到主线程")
}
}
输出结果:
global - 耗时操作
main - 完成耗时操作,回到主线程
其他方法
延时执行
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
}
DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
}
延时执行封装
typealias Task = (_ cancel : Bool) -> Void
func delay(_ time: TimeInterval, task: @escaping ()->()) -> Task? {
func dispatch_later(block: @escaping ()->()) {
let t = DispatchTime.now() + time
DispatchQueue.main.asyncAfter(deadline: t, execute: block)
}
var closure: (()->Void)? = task
var result: Task?
let delayedClosure: Task = {
cancel in
if let internalClosure = closure {
if (cancel == false) {
DispatchQueue.main.async(execute: internalClosure)
}
}
closure = nil
result = nil
}
result = delayedClosure
dispatch_later {
if let delayedClosure = result {
delayedClosure(false)
}
}
return result;
}
func cancel(_ task: Task?) {
task?(true)
}
执行一次
swift3.0之前:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
}
}
从swift3.0开始,dispatch_once被废弃了,上述写法已经不再被支持了,可使用其它方法实现。
OC写法:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只执行1次的代码(这里面默认是线程安全的)");
});
快速迭代
会阻塞主线程
print("begin")
DispatchQueue.concurrentPerform(iterations: 10) { (index) in
print(index)
}
print("end")
队列组
notify
使用concurrent
并行队列 + async
异步,执行则各任务同步打印,全部完成后执行notify
。
使用concurrent
并行队列 + sync
同步,则各任务按顺序打印,全部完成后执行notify
。
使用serial
串行队列 + async
异步(或sync
同步),则各任务按顺序打印,全部完成后执行notify
。
let group = DispatchGroup()
let queue = DispatchQueue.global()
group.enter()
queue.async {
self.download { (path) in
print("任务 1")
group.leave()
}
}
group.enter()
queue.async {
self.download { (path) in
print("任务 2")
group.leave()
}
}
group.notify(queue: queue) {
print("任务 3")
}
print("任务 4")
notify
不会阻塞主线程,先执行任务4
,任务1
和任务2
同步执行,等任务1
和任务2
全部执行完毕后执行任务3
wait()
let group = DispatchGroup()
let queue = DispatchQueue.global()
group.enter()
queue.async {
Thread.sleep(forTimeInterval: 3)
print("任务 1")
group.leave()
}
group.enter()
queue.async {
Thread.sleep(forTimeInterval: 2)
print("任务 2")
group.leave()
}
group.wait()
print("任务 3")
wait()
会阻塞主线程,需要等任务1
和任务2
全部执行完毕后才能执行任务3
信号量
使用serial
串行队列 + async
异步,则各任务按顺序打印,全部完成后执行notify
let semaphore = DispatchSemaphore(value: 1)//创建一个 Semaphore 并初始化信号的总量
let queue = DispatchQueue.global()
semaphore.wait()//可以使总信号量减 1,信号总量小于 0 时就会一直等待(阻塞所在线程),否则就可以正常执行。
queue.async {
Thread.sleep(forTimeInterval: 3)
print("任务1")
semaphore.signal()//发送一个信号,让信号总量加 1
}
semaphore.wait()
queue.async {
Thread.sleep(forTimeInterval: 2)
print("任务2")
semaphore.signal()
}
print("任务3")
栅栏
在执行完栅栏前面的操作之后,才执行栅栏操作,最后再执行栅栏后边的操作。
let concurrentQueue = DispatchQueue(label: "com.mouos.concurrent.queue", attributes: .concurrent)
concurrentQueue.async {
Thread.sleep(forTimeInterval: 5)
print("任务1")
}
concurrentQueue.async {
Thread.sleep(forTimeInterval: 3)
print("任务2")
}
concurrentQueue.async(group: nil, qos: .default, flags: .barrier) {
print("任务3")
}
concurrentQueue.async {
Thread.sleep(forTimeInterval: 2)
print("任务4")
}
concurrentQueue.async {
Thread.sleep(forTimeInterval: 2)
print("任务5")
}
任务1
和任务2
同步执行完成后,执行栅栏任务3
,等栅栏任务3
执行完毕后同步执行任务4
和任务5