任务与队列 iOS之多线程GCD(一)

栏目: IOS · 发布时间: 5年前

内容简介:特点:先进先出的数据结构分类:串行队列 并行队列 全局并行队列 主队列任务:就是block代码快要执行的代码 同步执行(sync) 异步执行(async)

队列

特点:先进先出的数据结构

分类:串行队列 并行队列 全局并行队列 主队列

任务:就是block代码快要执行的代码 同步执行(sync) 异步执行(async)

多线程 简单理解就是除主线程外开辟了其他线程、增加执行效率。大白话就是代码有多条执行路径。对于单核的iOS系统、多线程之间其实是并发的而不是多核的并行。也就是单核的iOS系统,各个线程在单位时间是来回切换的、造成了并行的假象。

GCD是基于 c语言 封装的、在这里只谈谈用法。用法就是创建队列,将任务添加到队列中执行。

如何创建队列?

串行队列
dispatch_queue_t queue1 = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL);
主队列 特殊的串行队列---所有主队列的任务都会放在主线程执行
dispatch_queue_t mainQueue = dispatch_get_main_queue();
并行队列
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
全局并行队列
dispatch_queue_t queueAll = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
复制代码

任务

任务分为同步执行、异步执行

同步不具备开启线程的能力
dispatch_sync(queue, ^{
    <#code#>
});
异步具备开启线程的能力、具体是否开启了线程要结合队列
dispatch_async(queue1, ^{
    <#code#>
});
复制代码

任务和队列组合 page表格截图如下:(由于全局并发队列也可以看作并发队列、所以不予考虑)

任务与队列 iOS之多线程GCD(一)

一、同步+串行队列

特点:不开启新的线程、任务按顺序执行

- (void)syncSerial {
    NSLog(@"当前线程为:%@",[NSThread currentThread]);  // 当前线程
    NSLog(@"开始");
    //这里创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        // 追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务三、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"结束");
}
复制代码

打印结果:

2019-01-23 09:49:41.098930+0800 多线程demo[922:34551] 当前线程为:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:41.099092+0800 多线程demo[922:34551] 开始
2019-01-23 09:49:43.100540+0800 多线程demo[922:34551] 我是任务一、来自线程:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:45.101953+0800 多线程demo[922:34551] 我是任务一、来自线程:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:47.103420+0800 多线程demo[922:34551] 我是任务二、来自线程:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:49.104828+0800 多线程demo[922:34551] 我是任务二、来自线程:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:51.106334+0800 多线程demo[922:34551] 我是任务三、来自线程:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:53.106785+0800 多线程demo[922:34551] 我是任务三、来自线程:<NSThread: 0x604000073a80>{number = 1, name = main}
2019-01-23 09:49:53.106981+0800 多线程demo[922:34551] 结束

复制代码

二、同步+并发队列

特点:不开启新的线程、任务按顺序执行

NSLog(@"当前线程%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开始");
    
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_sync(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_sync(queue, ^{
        // 追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务三、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"结束");
复制代码

打印结果:

2019-01-23 10:02:31.505366+0800 多线程demo[1053:44225] 当前线程<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:31.505740+0800 多线程demo[1053:44225] 开始
2019-01-23 10:02:33.506119+0800 多线程demo[1053:44225] 我是任务一、来自线程:<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:35.507093+0800 多线程demo[1053:44225] 我是任务一、来自线程:<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:37.507964+0800 多线程demo[1053:44225] 我是任务二、来自线程:<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:39.508543+0800 多线程demo[1053:44225] 我是任务二、来自线程:<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:41.509973+0800 多线程demo[1053:44225] 我是任务三、来自线程:<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:43.511403+0800 多线程demo[1053:44225] 我是任务三、来自线程:<NSThread: 0x600000064d00>{number = 1, name = main}
2019-01-23 10:02:43.511608+0800 多线程demo[1053:44225] 结束
复制代码

三、异步+串行队列

特点:开启了新的线程、任务顺序执行

NSLog(@"当前线程%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开始");
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        // 追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务三、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"结束");
复制代码

打印结果:

2019-01-23 10:09:26.140699+0800 多线程demo[1116:48819] 当前线程<NSThread: 0x600000076040>{number = 1, name = main}
2019-01-23 10:09:26.140906+0800 多线程demo[1116:48819] 开始
2019-01-23 10:09:26.141049+0800 多线程demo[1116:48819] 结束
2019-01-23 10:09:28.143936+0800 多线程demo[1116:48854] 我是任务一、来自线程:<NSThread: 0x6000004629c0>{number = 3, name = (null)}
2019-01-23 10:09:30.148732+0800 多线程demo[1116:48854] 我是任务一、来自线程:<NSThread: 0x6000004629c0>{number = 3, name = (null)}
2019-01-23 10:09:32.154261+0800 多线程demo[1116:48854] 我是任务二、来自线程:<NSThread: 0x6000004629c0>{number = 3, name = (null)}
2019-01-23 10:09:34.156924+0800 多线程demo[1116:48854] 我是任务二、来自线程:<NSThread: 0x6000004629c0>{number = 3, name = (null)}
2019-01-23 10:09:36.158106+0800 多线程demo[1116:48854] 我是任务三、来自线程:<NSThread: 0x6000004629c0>{number = 3, name = (null)}
2019-01-23 10:09:38.162608+0800 多线程demo[1116:48854] 我是任务三、来自线程:<NSThread: 0x6000004629c0>{number = 3, name = (null)}
复制代码

四、异步+并发队列

特点:开启新的线程、任务交替执行

NSLog(@"当前线程%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开始");
    
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];            
            NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        // 追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务三、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"结束");
复制代码

打印结果:

2019-01-23 10:15:29.424356+0800 多线程demo[1190:53683] 当前线程<NSThread: 0x604000074740>{number = 1, name = main}
2019-01-23 10:15:29.424575+0800 多线程demo[1190:53683] 开始
2019-01-23 10:15:29.424723+0800 多线程demo[1190:53683] 结束
2019-01-23 10:15:31.430195+0800 多线程demo[1190:53767] 我是任务三、来自线程:<NSThread: 0x60400047f5c0>{number = 5, name = (null)}
2019-01-23 10:15:31.430195+0800 多线程demo[1190:53764] 我是任务二、来自线程:<NSThread: 0x600000278a80>{number = 3, name = (null)}
2019-01-23 10:15:31.430195+0800 多线程demo[1190:53763] 我是任务一、来自线程:<NSThread: 0x60400047fe40>{number = 4, name = (null)}
2019-01-23 10:15:33.435111+0800 多线程demo[1190:53763] 我是任务一、来自线程:<NSThread: 0x60400047fe40>{number = 4, name = (null)}
2019-01-23 10:15:33.435111+0800 多线程demo[1190:53767] 我是任务三、来自线程:<NSThread: 0x60400047f5c0>{number = 5, name = (null)}
2019-01-23 10:15:33.435111+0800 多线程demo[1190:53764] 我是任务二、来自线程:<NSThread: 0x600000278a80>{number = 3, name = (null)}
复制代码

五、异步+主队列(任务执行 类似为同步+串行队列)

特点:主线程执行(主队列的任务都是在主线程)、任务按顺序执行

NSLog(@"当前线程为:%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开始");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_async(queue, ^{
        // 追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"我是任务三、来自线程:%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    NSLog(@"结束");
复制代码

打印结果:

2019-01-23 10:19:33.503411+0800 多线程demo[1242:56892] 当前线程为:<NSThread: 0x60000006eac0>{number = 1, name = main}
2019-01-23 10:19:33.503588+0800 多线程demo[1242:56892] 开始
2019-01-23 10:19:33.503736+0800 多线程demo[1242:56892] 结束
2019-01-23 10:19:35.538348+0800 多线程demo[1242:56892] 我是任务一、来自线程:<NSThread: 0x60000006eac0>{number = 1, name = main}
2019-01-23 10:19:37.539726+0800 多线程demo[1242:56892] 我是任务一、来自线程:<NSThread: 0x60000006eac0>{number = 1, name = main}
2019-01-23 10:19:39.541125+0800 多线程demo[1242:56892] 我是任务二、来自线程:<NSThread: 0x60000006eac0>{number = 1, name = main}
2019-01-23 10:19:41.542511+0800 多线程demo[1242:56892] 我是任务二、来自线程:<NSThread: 0x60000006eac0>{number = 1, name = main}
2019-01-23 10:19:43.543439+0800 多线程demo[1242:56892] 我是任务三、来自线程:<NSThread: 0x60000006eac0>{number = 1, name = main}
2019-01-23 10:19:45.544663+0800 多线程demo[1242:56892] 我是任务三、来自线程:<NSThread: 0x60000006eac0>{number = 1, name = main}
复制代码

六、同步+主队列

特点:队列引起的死锁

- (void)syncMain {
    NSLog(@"当前线程:%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开始");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_sync(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束");
}
复制代码

打印结果:

2019-01-23 10:25:00.640438+0800 多线程demo[1307:61022] 当前线程:<NSThread: 0x600000069a80>{number = 1, name = main}
2019-01-23 10:25:00.640607+0800 多线程demo[1307:61022] 开始
(lldb) 崩溃
复制代码

分析:由于主队列是串行队列、我们把syncMain方法看成一个任务、任务一看成一个任务。由于这两个任务都在主队列执行。主队列是特殊的串行队列。特点是任务按顺序执行。所以先执行syncMain、而syncMain要等任务一执行完才能结束。任务一要等syncMain结束再执行。两个任务互相等待。造成死锁。这就是为什么同步在主队列执行会死锁而同步在串行队列不死锁的原因。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++编程思想(第1卷)

C++编程思想(第1卷)

[美] Bruce Eckel / 刘宗田、袁兆山、潘秋菱 / 机械工业出版社 / 2002-9 / 59.00元

《C++编程思考》第2版与第1版相比,在章节安排上有以下改变。增加了两章:“对象的创建与使用”和“C++中的C”,前者与“对象导言”实际上是第1版“对象的演化”一章的彻底重写,增加了近几年面向对象方法和编程方法的最瓣研究与实践的有效成果,后者的添加使不熟悉C的读者可以直接使用这本书。删去了四章:“输入输出流介绍”、“多重继承”、“异常处理”和“运行时类型识别”,删去的内容属于C++中较复杂的主题,......一起来看看 《C++编程思想(第1卷)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具