iOS GCD

2020-06-19  本文已影响0人  gaookey

任务和队列的创建方法 / 获取方法

队列的创建方法 / 获取方法

串行队列的创建方法

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

上一篇 下一篇

猜你喜欢

热点阅读