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)}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容