当前位置: 首页 > article >正文

【iOS】GCD学习

GCD的概念

GCD(Grand Central Dispatch),是有Apple公司开发的一个多核编程的解决方案,用以优化应用程序支持多核处理器,是基于线程模式之上执行并发任务。

GCD的优点

  1. 利用设备多核进行并行运算
  2. GCD自动充分使用设备的CPU内核
  3. GCD自动管理线程的生命周期(线程创建、线程调度、线程销毁)
  4. 使用简单

GCD任务和队列

任务

任务就是执行操作,即可以执行的代码;执行任务有两种方式:同步 和 异步。

  • 同步执行: 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。不具备开启新线程的能力。
  • 异步执行:异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。可以在新的线程中执行任务,具备开启新线程的能力。

队列

Dispatch Queue指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,遵循 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务;在 GCD 中有两种队列:串行队列 和 并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。

  • 串行队列:每次只有一个任务被执行。让任务一个接着一个地执行。
  • 并发队列:可以让多个任务同时执行。(可以开启多个线程,并且同时执行任务)。

CGD使用步骤

  1. 创建队列
  2. 将任务追加到任务的等待队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)。

创建队列的方法

  1. 可以使用 dispatch_queue_create 方法来创建队列。该方法需要传入两个参数:
  • 第一个参数表示队列的唯一标识符,用于 DEBUG,可为空。队列的名称推荐使用应用程序 ID 这种逆序全程域名。
  • 第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL 表示串行队列,DISPATCH_QUEUE_CONCURRENT 表示并发队列。
// 串行队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
  1. 对于串行队列,GCD 默认提供了:『主队列(Main Dispatch Queue)』。
  • 所有放在主队列中的任务,都会放到主线程中执行。
  • 可使用 dispatch_get_main_queue() 方法获得主队列。
// 主队列的获取方法
dispatch_queue_t queue = dispatch_get_main_queue();

创建任务的方法

GCD 提供了同步执行任务的创建方法 dispatch_sync 和异步执行任务创建方法 dispatch_async。

同步任务: dispatch_sync:

 // 同步执行任务创建方法
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%s",__func__);
    });

异步任务: dispatch_async

  // 异步执行任务创建方法
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%s",__func__);
 
    });

任务和队列不同组合方式的区别:

区别并发队列串行队列主队列
同步(sync)没有开启新线程,串行执行任务没有开启新线程,串行执行任务死锁卡住不执行
异步(async有开启新线程,并发执行任务有开启新线程(1条),串行执行任务没有开启新线程,串行执行任务

注意:从上边可看出: 『主线程』 中调用 『主队列』+『同步执行』 会导致死锁问题。
这是因为 主队列中追加的同步任务 和 主线程本身的任务 两者之间相互等待,阻塞了 『主队列』,最终造成了主队列所在的线程(主线程)死锁问题。
而如果我们在 『其他线程』 调用 『主队列』+『同步执行』,则不会阻塞 『主队列』,自然也不会造成死锁问题。最终的结果是:不会开启新线程,串行执行任务。

CGD的组合使用

串行队列 + 同步执行

不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。

  /**
     * 串行队列 + 同步执行
     * 特点:不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。
     */
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
            // 追加任务 1
            [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
            // 追加任务 2
            [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
            // 追加任务 3
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"syncSerial---end");

运行结果:
在这里插入图片描述

串行队列 + 异步执行

会开启新线程。执行完一个任务,再执行下一个任务。

 /**
     * 串行队列 + 异步执行
     * 特点:会开启新线程。执行完一个任务,再执行下一个任务。
     */
    dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
            // 任务 1
            [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 2
            [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 3
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"asyncSerial---end");

运行结果:
在这里插入图片描述

并发队列 + 同步执行

不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。

  /**
    * 并发队列 + 同步执行
    * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
    */
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
           // 任务 1
           [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
           NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
           // 任务 2
           [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
           NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
           // 任务 3
           [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
           NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"syncConcurrent---end");

运行结果:
在这里插入图片描述

并发队列 + 异步执行

可以开启多个线程,任务同时执行。

   /**
     * 并发队列 + 异步执行
     * 特点:可以开启多个线程,任务同时执行。
     */
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
            // 任务 1
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 2
            [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 3
            [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"asyncConcurrent---end");

运行结果:
在这里插入图片描述

同步执行 + 主队列

在主线程中调用 『同步执行 + 主队列』

互相等待卡住不可行

/**
 * 同步执行 + 主队列
 * 特点(主线程调用):互等卡主不执行。
 * 特点(其他线程调用):不会开启新线程,执行完一个任务,再执行下一个任务。
 */
- (void)syncMain {
    
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"syncMain---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_sync(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_sync(queue, ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_sync(queue, ^{
        // 追加任务 3
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    NSLog(@"syncMain---end");
}

在其他线程中调用『同步执行 + 主队列』

不会开启新线程,执行完一个任务,再执行下一个任务

// 使用 NSThread 的 detachNewThreadSelector 方法会创建线程,并自动启动线程执行 selector 任务
[NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];

异步执行 + 主队列

只在主线程中执行任务,执行完一个任务,再执行下一个任务。

/**
 * 异步执行 + 主队列
 * 特点:只在主线程中执行任务,执行完一个任务,再执行下一个任务
 */
- (void)asyncMain {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"asyncMain---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_async(queue, ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_async(queue, ^{
        // 追加任务 3
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    NSLog(@"asyncMain---end");
}

结果:
在这里插入图片描述


http://www.kler.cn/a/16311.html

相关文章:

  • 试编写算法将单链表就地逆置(默认是带头节 点,如果是不带头节点地逆置呢?)
  • 第四十五章 Vue之Vuex模块化创建(module)
  • 开源模型应用落地-qwen模型小试-Qwen2.5-7B-Instruct-tool usage入门-集成心知天气(二)
  • 【PowerHarmony】电鸿蒙学习记录-编写helloworld!
  • git入门环境搭建
  • 使用API有效率地管理Dynadot域名,编辑账户中whois联系人信息
  • 【机器学习学习】第一天:入门指南
  • spring
  • QT实现固高运动控制卡示波器
  • 【SQL篇】面试篇之子查询
  • 一文解决MySQL突击面试,关键知识点总结
  • 解除Word的编辑保护【简单版】
  • 智能网联汽车城市化的进程和思考
  • next(), nextLine(),nextInt()报错分析
  • UG NX二次开发(C++)-建模-修改NXObject或者Feature的颜色(一)
  • Java学习报培训班好还是自学好?
  • 微服务SpringCloud面试题27问
  • appium-app测试-环境搭建手机和adb设置
  • 四和能聚分析做直播带货的商家通常发布什么类型的短视频
  • 电脑的选择
  • 06.toRef 和 toRefs
  • iOS 多线程使用示例
  • JSP 的本质原理解析:“编写的时候是JSP,心里想解读的是 java 源码“
  • 什么是Java中的反射机制?
  • Syncfusion Essential Studio Enterprise 2023.1 Crack
  • AOSP编译问题