zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

iOS 多线程 swift5 GCD 自己消化的

ios多线程 自己 gcd swift5
2023-09-14 09:04:14 时间

1.串行并行,同步异步

  • 并行队列同步执行,串行队列同步和异步执行,执行顺序是确定的
    请添加图片描述

1.1 串行队列 + 同步执行

主队列:死锁

请添加图片描述
请添加图片描述

自定义串行队列:顺序执行,和正常执行代码一样

请添加图片描述

    override func viewDidLoad() {
        super.viewDidLoad()
        print("start:\(Thread.current)")
        syncSerial()
        sleep(3)
        print("end:\(Thread.current)")
    }
    
    //串行队列 + 同步执行
    func syncSerial() {
        let serialQueue = DispatchQueue(label: "serial")
        
        for i in 0...10 {
            serialQueue.sync {
                print("\(i):\(Thread.current)")
            }
        }
    }

打印结果:
start:<NSThread: 0x600003f906c0>{number = 1, name = main}
0:<NSThread: 0x600003f906c0>{number = 1, name = main}
1:<NSThread: 0x600003f906c0>{number = 1, name = main}
2:<NSThread: 0x600003f906c0>{number = 1, name = main}
3:<NSThread: 0x600003f906c0>{number = 1, name = main}
4:<NSThread: 0x600003f906c0>{number = 1, name = main}
5:<NSThread: 0x600003f906c0>{number = 1, name = main}
6:<NSThread: 0x600003f906c0>{number = 1, name = main}
7:<NSThread: 0x600003f906c0>{number = 1, name = main}
8:<NSThread: 0x600003f906c0>{number = 1, name = main}
9:<NSThread: 0x600003f906c0>{number = 1, name = main}
10:<NSThread: 0x600003f906c0>{number = 1, name = main}
end:<NSThread: 0x600003f906c0>{number = 1, name = main}

请添加图片描述

1.2 并行队列 + 同步执行:不开启线程,按代码顺序执行

请添加图片描述

1.3 串行队列 + 异步执行:一般只会新开一个线程

自定义串行队列:开启新线程,几个新线程中的任务和主线程中的任务并发执行

  • end什么时候打印不确定
    override func viewDidLoad() {
        super.viewDidLoad()
        print("start:\(Thread.current)")
        asyncSerial()
        print("end:\(Thread.current)")
    }
    
    //串行队列 + 异步执行
    func asyncSerial(){
        let serialQueue = DispatchQueue(label: "serial")
        for i in 0...10 {
            serialQueue.async {
                print("\(i):\(Thread.current)")
            }
        }
    }

打印结果:
start:<NSThread: 0x6000033cc900>{number = 1, name = main}
0:<NSThread: 0x60000338c340>{number = 3, name = (null)}
end:<NSThread: 0x6000033cc900>{number = 1, name = main}
1:<NSThread: 0x60000338c340>{number = 3, name = (null)}
2:<NSThread: 0x60000338c340>{number = 3, name = (null)}
3:<NSThread: 0x60000338c340>{number = 3, name = (null)}
4:<NSThread: 0x60000338c340>{number = 3, name = (null)}
5:<NSThread: 0x60000338c340>{number = 3, name = (null)}
6:<NSThread: 0x60000338c340>{number = 3, name = (null)}
7:<NSThread: 0x60000338c340>{number = 3, name = (null)}
8:<NSThread: 0x60000338c340>{number = 3, name = (null)}
9:<NSThread: 0x60000338c340>{number = 3, name = (null)}
10:<NSThread: 0x60000338c340>{number = 3, name = (null)}

请添加图片描述
请添加图片描述

主队列:不开启新线程,会被放到最后面

  • 执行顺序始终是:start -> end -> 然后按顺序执行for循环里的任务
    override func viewDidLoad() {
        super.viewDidLoad()
        print("start:\(Thread.current)")
        asyncSerial()
        sleep(3)
        print("end:\(Thread.current)")
    }
    
    //串行队列 + 异步执行
    func asyncSerial(){
        let serialQueue = DispatchQueue.main
        for i in 0...10 {
            serialQueue.async {
                print("\(i):\(Thread.current)")
            }
        }
    }

1.4 并发队列(自定义) + 异步执行

动画

  • 并行队列异步执行:执行顺序不确定
    请添加图片描述

代码1: for循环在queue.async里

  • print(“end:(Thread.current)”)什么时候执行是不确定的
  • 并发队列中只添加了一任务,这个任务是按顺序执行的,始终会按顺序打印出i
    override func viewDidLoad() {
        super.viewDidLoad()
        print("start:\(Thread.current)")
        asyncConcurrent()
        sleep(1)
        print("end:\(Thread.current)")
    }
    
    //并发队列 + 异步执行
    func asyncConcurrent()
    {
        let queue = DispatchQueue(label: "concurrence", qos: .userInteractive, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
        
        queue.async {
            for i in 0...10 {
                print("\(i):\(Thread.current)")
            }
        }
    }

打印结果:
start:<NSThread: 0x6000018d4440>{number = 1, name = main}
0:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
1:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
2:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
3:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
4:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
5:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
6:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
7:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
8:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
9:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
10:<NSThread: 0x60000188cbc0>{number = 6, name = (null)}
end:<NSThread: 0x6000018d4440>{number = 1, name = main}

注释掉sleep(1)后的打印结果
start:<NSThread: 0x60000253c800>{number = 1, name = main}
end:<NSThread: 0x60000253c800>{number = 1, name = main}
0:<NSThread: 0x600002560140>{number = 5, name = (null)}
1:<NSThread: 0x600002560140>{number = 5, name = (null)}
2:<NSThread: 0x600002560140>{number = 5, name = (null)}
3:<NSThread: 0x600002560140>{number = 5, name = (null)}
4:<NSThread: 0x600002560140>{number = 5, name = (null)}
5:<NSThread: 0x600002560140>{number = 5, name = (null)}
6:<NSThread: 0x600002560140>{number = 5, name = (null)}
7:<NSThread: 0x600002560140>{number = 5, name = (null)}
8:<NSThread: 0x600002560140>{number = 5, name = (null)}
9:<NSThread: 0x600002560140>{number = 5, name = (null)}
10:<NSThread: 0x600002560140>{number = 5, name = (null)}

代码2:queue.async在for循环里

  • print(“end:(Thread.current)”)什么时候执行是不确定的
  • 并发队列中的多个任务执行顺序不确定
    //并发队列 + 异步执行
    func asyncConcurrent()
    {
        let queue = DispatchQueue(label: "concurrence", qos: .userInteractive, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
        
        print("start:\(Thread.current)")
        
        for i in 0...100 {
            queue.async {
                print("\(i):\(Thread.current)")
            }
        }

        print("end:\(Thread.current)")
    }

打印结果:
start:<NSThread: 0x600003ac48c0>{number = 1, name = main}
0:<NSThread: 0x600003a86600>{number = 4, name = (null)}
1:<NSThread: 0x600003a8dec0>{number = 5, name = (null)}
4:<NSThread: 0x600003a86600>{number = 4, name = (null)}
2:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
6:<NSThread: 0x600003a8dec0>{number = 5, name = (null)}
5:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
3:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
7:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
8:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
9:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
10:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
11:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
12:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
13:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
14:<NSThread: 0x600003a8dec0>{number = 5, name = (null)}
15:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
16:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
17:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
18:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
19:<NSThread: 0x600003a8dec0>{number = 5, name = (null)}
20:<NSThread: 0x600003a86600>{number = 4, name = (null)}
21:<NSThread: 0x600003a8dec0>{number = 5, name = (null)}
22:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
24:<NSThread: 0x600003aa6380>{number = 9, name = (null)}
23:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
25:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
26:<NSThread: 0x600003ab1ec0>{number = 10, name = (null)}
27:<NSThread: 0x600003aa6000>{number = 11, name = (null)}
89:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
91:<NSThread: 0x600003aa6000>{number = 11, name = (null)}
30:<NSThread: 0x600003abd100>{number = 14, name = (null)}
92:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
32:<NSThread: 0x600003aa7440>{number = 16, name = (null)}
33:<NSThread: 0x600003ab24c0>{number = 17, name = (null)}
95:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
96:<NSThread: 0x600003aa7440>{number = 16, name = (null)}
35:<NSThread: 0x600003ab30c0>{number = 19, name = (null)}
97:<NSThread: 0x600003ab24c0>{number = 17, name = (null)}
38:<NSThread: 0x600003aa7540>{number = 22, name = (null)}
39:<NSThread: 0x600003abd2c0>{number = 23, name = (null)}
40:<NSThread: 0x600003a81040>{number = 24, name = (null)}
41:<NSThread: 0x600003ab1440>{number = 25, name = (null)}
42:<NSThread: 0x600003aa6580>{number = 26, name = (null)}
43:<NSThread: 0x600003a89040>{number = 27, name = (null)}
44:<NSThread: 0x600003ab15c0>{number = 28, name = (null)}
45:<NSThread: 0x600003abd580>{number = 29, name = (null)}
end:<NSThread: 0x600003ac48c0>{number = 1, name = main}
46:<NSThread: 0x600003aa7740>{number = 30, name = (null)}
47:<NSThread: 0x600003a8b700>{number = 31, name = (null)}
48:<NSThread: 0x600003abd640>{number = 32, name = (null)}
49:<NSThread: 0x600003aa7800>{number = 33, name = (null)}
50:<NSThread: 0x600003a8ad00>{number = 34, name = (null)}
51:<NSThread: 0x600003abd700>{number = 35, name = (null)}
52:<NSThread: 0x600003aa7a40>{number = 36, name = (null)}
53:<NSThread: 0x600003ab3bc0>{number = 37, name = (null)}
54:<NSThread: 0x600003abd7c0>{number = 38, name = (null)}
55:<NSThread: 0x600003aa7980>{number = 39, name = (null)}
56:<NSThread: 0x600003ab3d40>{number = 40, name = (null)}
57:<NSThread: 0x600003abd880>{number = 41, name = (null)}
58:<NSThread: 0x600003aa7880>{number = 42, name = (null)}
59:<NSThread: 0x600003ab3e40>{number = 43, name = (null)}
60:<NSThread: 0x600003a8a040>{number = 44, name = (null)}
61:<NSThread: 0x600003aaffc0>{number = 45, name = (null)}
62:<NSThread: 0x600003ab3e80>{number = 46, name = (null)}
63:<NSThread: 0x600003abd940>{number = 47, name = (null)}
64:<NSThread: 0x600003ab3f40>{number = 48, name = (null)}
65:<NSThread: 0x600003aaff00>{number = 49, name = (null)}
66:<NSThread: 0x600003abda40>{number = 50, name = (null)}
67:<NSThread: 0x600003ab1180>{number = 51, name = (null)}
68:<NSThread: 0x600003a8a100>{number = 52, name = (null)}
69:<NSThread: 0x600003aafe40>{number = 53, name = (null)}
70:<NSThread: 0x600003abdb00>{number = 54, name = (null)}
71:<NSThread: 0x600003a895c0>{number = 55, name = (null)}
72:<NSThread: 0x600003ab2080>{number = 56, name = (null)}
73:<NSThread: 0x600003abdbc0>{number = 57, name = (null)}
74:<NSThread: 0x600003aafd40>{number = 58, name = (null)}
75:<NSThread: 0x600003a89a40>{number = 59, name = (null)}
76:<NSThread: 0x600003abdc80>{number = 60, name = (null)}
77:<NSThread: 0x600003aafc40>{number = 61, name = (null)}
78:<NSThread: 0x600003a89180>{number = 62, name = (null)}
79:<NSThread: 0x600003aafb80>{number = 63, name = (null)}
80:<NSThread: 0x600003abdd40>{number = 64, name = (null)}
81:<NSThread: 0x600003a8bd00>{number = 65, name = (null)}
82:<NSThread: 0x600003aafac0>{number = 66, name = (null)}
83:<NSThread: 0x600003abde40>{number = 67, name = (null)}
84:<NSThread: 0x600003a86600>{number = 4, name = (null)}
85:<NSThread: 0x600003a8dec0>{number = 5, name = (null)}
86:<NSThread: 0x600003a98b80>{number = 3, name = (null)}
87:<NSThread: 0x600003aa6380>{number = 9, name = (null)}
88:<NSThread: 0x600003aa66c0>{number = 7, name = (null)}
28:<NSThread: 0x600003aa0000>{number = 12, name = (null)}
90:<NSThread: 0x600003ab1ec0>{number = 10, name = (null)}
29:<NSThread: 0x600003abd080>{number = 13, name = (null)}
31:<NSThread: 0x600003ab1b00>{number = 15, name = (null)}
93:<NSThread: 0x600003aa6000>{number = 11, name = (null)}
94:<NSThread: 0x600003abd100>{number = 14, name = (null)}
34:<NSThread: 0x600003abd1c0>{number = 18, name = (null)}
36:<NSThread: 0x600003aa73c0>{number = 20, name = (null)}
37:<NSThread: 0x600003abd280>{number = 21, name = (null)}
98:<NSThread: 0x600003aa0640>{number = 8, name = (null)}
100:<NSThread: 0x600003aa7440>{number = 16, name = (null)}
99:<NSThread: 0x600003ab30c0>{number = 19, name = (null)}

1.5 串行和同步的区别:串行是按任务添加的先后顺序执行,同步是按代码书写(执行)的顺序执行

  • 在主队列中同步串行会发生死锁,就是因为这个两个执行顺序发生冲突,引起循环等待

1.6 其他实例测试

实例一

请添加图片描述
请添加图片描述

实例二

请添加图片描述
请添加图片描述

请添加图片描述

实例三

请添加图片描述

参考博客:

iOS线程间通信 - GCD篇
iOS线程间通信 - NSThread篇
iOS开发 swift5 – GCD
我的另外一篇博客:GCD

疑问:

1.同步并行会死锁吗
2.同步和串行的区别