iOS之线程(二)GCD

本文深入解析GCD(Grand Central Dispatch)的原理与应用,涵盖任务、队列、异步与同步函数,以及并发、串行队列的区别。通过实例演示如何使用GCD进行线程管理和优化多核并行运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 概念

  • GCD:Gtand Central Dispatch 中枢调度器
  • GCD主要解决的是多核并行运算
  • GCD是自动管理线程的生命周期的
1.1 任务
  • 要执行的操作
  • 同步函数:在当前线程中执行任务,不具备开启新线程的能力,立马在当前线程绕那个同步执行任务
  • 异步函数:可以在新的线程中执行任务,具备开启新线程的能力
1.2 队列
  • 用来存放任务
  • 并发队列(异步函数才有效)
  • 串行队列
1.3 一般使用情况
  • 声明一个任务
  • 将任务添加到队列中
    • GCD会自动将队列中的任务取出,放到对应的线程中去
    • 任务要遵循队列的FIFO原则,先进先出,后进后出
使用并发队列串行队列主队列
异步函数【1】具备开启新线程的能力【2】开启新的线程,任务异步执行【1】具备开启线程的能力【2】会开线程,开一条线程,队列中的任务是按照先后顺序执行【1】不会开启新的线程 【2】串行执行
同步函数【1】不会开启新的线程【2】串行执行任务【1】不会开启新的线程【2】串行执行任务【1】如果在主线程中执行会发生死锁【2】在子线程可以
2. 异步函数并发队列
  • 异步函数 :具备开启新线程的能力
  • 异步函数 + 并发队列 ->开新线程,队列中的任务是异步执行
 /*
     参数一: C语言的字符串,标识符用来区分队列
     参数二: 队列的类型
     DISPATCH_QUEUE_CONCURRENT 并发队列
     DISPATCH_QUEUE_SERIAL 串行队列
     */
    //创建一个队列
    dispatch_queue_t queue = dispatch_queue_create("www.cc.com", DISPATCH_QUEUE_CONCURRENT);
    //声明任务
    //第一个参数:队列
    //要执行的任务
   // dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
    dispatch_async(queue, ^{
        
        NSLog(@"111111,--%@",[NSThread currentThread]);
    });


注意: 一个队列中可以.可以添加多个任务,CGD开启线程是不受控制的,不是说有多少个任务就开启多少条线程,具体的是系统内部决定的

3. 异步函数 串行队列
  • 异步函数 :具备开启新线程的能力
  • 异步函数 + 串行队列: 会开线程,开一条线程,队列中的任务是按照先后顺序执行
 //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("cc", DISPATCH_QUEUE_SERIAL);
    //创建异步函数任务
    dispatch_async(queue, ^{
        NSLog(@"2222222--%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3333--%@",[NSThread currentThread]);
    });
    

其实上面的创建的并发队列,可以换成系统的全局并发队列,区别:上面是自己手动创建的并发队列,下面是获取系统的

//获取全局并发队列
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    

4. 同步函数+并发队列

  • 同步函数:不具备开启新线程的能力
  • 同步函数+并发队列:不会开启子线程,串行执行任务
//创建队列
    dispatch_queue_t queue = dispatch_queue_create("hhh", DISPATCH_QUEUE_CONCURRENT);
    //创建任务
    //同步函数
    dispatch_sync(queue, ^{
        NSLog(@"999--%@",[NSThread currentThread]);
    });
    
    // 999--<NSThread: 0x60000155a240>{number = 1, name = main}


5. 同步函数+串行队列

  • 同步函数:不具备开启新线程的能力
  • 同步函数+串行队列:不会开启新的线程
 //创建队列
    dispatch_queue_t queue = dispatch_queue_create("kkk", DISPATCH_QUEUE_SERIAL);
    //同步函数
    dispatch_sync(queue, ^{
        
        NSLog(@"%@",[NSThread currentThread]);
    });

6.主队列

  • 主队列是GCD自带的一种比较特殊的串行队列
  • 在主队列中的任务,都是在主线程中执行的
  • 获取主队列 dispatch_get_main_queue()
6.1异步函数+主队列
  • 不会开启子线程
   // 获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //异步函数执行
    dispatch_async(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
6.2 同步函数 + 主队列
  • 同步函数:不具备开启新线程能力,立马执行如果这个任务没有执行完,不会执行下一个任务
  • 产生:死锁
   // 获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //同步函数执行
    dispatch_sync(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });


6.3 线程产生死锁

造成死锁的条件: 使用同步sync函数 往当前 串行( SERIAL)队列 添加任务, 会卡住当前任务造成死锁

线程死锁
dispatch_sync同步:立马执行当前线程中的任务,执行完毕才能继续往下执行
FIFO原则: 先进的先出

意思就是: 整个函数 viewdidload执行完,打印333,才可以执行 同步的任务 打印222, 由于同步函数sync 要立马执行当前任务,打印222,才可以执行打印333,所以会产生死锁
在这里插入图片描述


//MARK:---线程产生死锁
- (void)GCDLock1{
  
    //原则: 同步线程 要立马执行
    // FIFO:先进先出的原则,那个任务 先进来 马哥现任县执行
    //GCDLock1 在主队列中,要先执行完 这个线程
    //dispatch_sync 队列要立马在当前线程执行, 所以会产生死锁
    //打印人3333 要先执行完,才会执行 打印2222,
    //然而 打印任务2222 要立马执行完,才会执行打印任务3333
    
    NSLog(@"11111");
    
    dispatch_queue_t que = dispatch_get_main_queue();
    dispatch_sync(que, ^{
          NSLog(@"22222");
    });
    
      NSLog(@"333333");
    
}


原因:
1,创建了一个 子线程
2.队列0 和 队列1 都在 子线程中执行
3.由于队列0 执行到 打印执行任务2时,遇到 同步函数,要立马执行函数内 队列1的任务, 此时队列0的打印任务4 还没有执行完, 所以要等打印任务4执行完,才可以执行 同步函数 队列1,造成了线程死锁

// MARK:---会产生死锁2
- (void)GCDLock3 {
    
     //会产生死锁
    
     // 原因: 1,创建了一个 子线程
    // 2.队列0 和 队列1 都在 子线程中执行
    // 3.由于队列0  执行到 打印执行任务2时,遇到 同步函数,要立马执行函数内 队列1的任务, 此时队列0的打印任务4  还没有执行完, 所以要等打印任务4执行完,才可以执行 同步函数 队列1,造成了线程死锁
    
      NSLog(@"执行任务1");
    //DISPATCH_QUEUE_SERIAL 串行队列
    dispatch_queue_t que = dispatch_queue_create("myque", DISPATCH_QUEUE_SERIAL);
    
    
       dispatch_async(que, ^{  // 线程 队列0
            NSLog(@"执行任务2");
           
        dispatch_sync(que, ^{ //线程 队列1
               
            NSLog(@"执行任务3");
           });
           
           
            NSLog(@"执行任务4");
           
       });
       
          NSLog(@"执行任务5");
}


7.线程之间的通信

  • 只要是主队列一定是在主线程执行的
- (void)setup7 {
    
    //1.获取全局并发队列
    dispatch_queue_t globalQue = dispatch_get_global_queue(0, 0);
    
    //异步函数执行
    dispatch_async(globalQue, ^{
    //URL
        NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559637616849&di=ac9047efc5fb0dbe9eb8d55e321ac4a5&imgtype=0&src=http%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2FzfDDxwQnD2Qib4s4tN6tVjeD9TXIedpicIZvKjL1u6MfRicUeAx9t31HLBrh11bfxhbiakH0te22TicfmCZgbErp3Gw%2F640%3Fwx_fmt%3Djpeg"];
        
        //回去二进制数据
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        //g回到主队列s刷新界面
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"回到主队列");
            self.imgageView.image = image;
        });
        
        
        
    });
    
    
}
8. GCD任务加强
//任务加强
- (void)demo1{
    //获取并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    //包装
    void(^task)(void) = ^{
        
        dispatch_sync(queue, ^{
            NSLog(@"1111---同步--%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"2222---异步步--%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"33333---异步步--%@",[NSThread currentThread]);
        });
        
        
    };
    //执行任务
    dispatch_async(queue, task);
    
    
}

在这里插入图片描述

在这里插入图片描述

9.栅栏函数

栅栏函数是:保证次函数前面的执行完,然后执行自己的栅栏函数,然后在执行 函数后面的线程
注意:
1.全局并发队列,对栅栏函数没有作用
2.使用栅栏函数,必须是自己手动创建的并发队列


//MARK:---栅栏函数

- (void)testBary {
    
    //群居并发队列
//    dispatch_queue_t que =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    
    //自己手动穿件的队列
    dispatch_queue_t que = dispatch_queue_create("cc", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(que, ^{
        NSLog(@"---%@---1----",[NSThread  currentThread]);
    });
    
    dispatch_async(que, ^{
         NSLog(@"---%@---2----",[NSThread  currentThread]);
    });
    
    dispatch_barrier_async(que, ^{
        NSLog(@"-栅栏函数--%@-------",[NSThread  currentThread]);
    });
    
    
    dispatch_async(que, ^{
           NSLog(@"---%@---3----",[NSThread  currentThread]);
       });
       
       dispatch_async(que, ^{
            NSLog(@"---%@---4----",[NSThread  currentThread]);
       });
       
    
}

10.同时执行函数 apply

我们知道 for循环是 执行一次循环,在执行下一次循环
有时我们在开发会遇到,多个任务同时执行的问题,比如:同时copy图片到另外一个文件夹中,此时就会用到 apply同时执行函数


- (void)viewDidLoad {
    [super viewDidLoad];
   
    // DISPATCH_QUEUE_PRIORITY_DEFAULT 默认队列
    dispatch_queue_t que = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //同时执行 并发队列 ,执行10不同的任务
    dispatch_apply(10, que, ^(size_t index) {
        NSLog(@"--%zd--%@---",index,[NSThread currentThread]);
    });

    
}

11.CGD 队列组 - group

- (void)demo1{
    //创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //创建任务组
    dispatch_group_t group = dispatch_group_create();
    //异步
    dispatch_group_async(group, queue, ^{
        NSLog(@"AAAA");
    });
     //异步
    dispatch_group_async(group, queue, ^{
        NSLog(@"bbbb");
    });
     //异步
    dispatch_group_async(group, queue, ^{
        NSLog(@"CCCC");
    });
    
    // 就是保证上面的3个任务 执行完毕 之后才执行  dispatch_group_notify
    //这个任务组完成的通知
    dispatch_group_notify(group, queue, ^{
        NSLog(@"所有的任务完成");
    });
    
    NSLog(@"11111");
}

12 .常用的函数
12.1一次性执行函数

//MARK:---一次性执行函数
- (void)testOnce{
    static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          NSLog(@"执行一次就b在执行了");
      });
}


12.2 常用的代码执行 延迟操作
//MARK:---延迟执行
- (void)testDiplay{
    
    //延迟2l秒执行
    [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
    
    //延迟3秒执行
    [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSLog(@"延迟4秒执行");
    });
    
}

- (void)run {
    NSLog(@"奔跑");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值