iOS开发 swift -- GCD

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)}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容