iOS底层原理之GCD的任务与队列

GCD

简介

Grand Central Dispatch(GCD)是 Apple 开发的一个多核编程的解决方法。它是一套纯 C 语言的 API,主要用于优化应用程序以支持多核处理器以及其余对称多处理系统。它是一个在线程池模式的基础上执行的并发任务。编程

GCD的优势

  • GCD支持多核并行计算
  • GCD自动管理线程的生命周期(线程的建立、调起、等待、销毁)
  • 使用者只需告知GCD执行任务

任务与队列

任务

任务即执行操做,就是线程中须要执行的代码。在GCD中就是放在block中执行的代码都是任务。任务分为同步任务(sync)异步任务(async)markdown

  • 同步任务(sync):同步添加到队列当中,当前面的任务没有执行完毕时会一直等待,直到前面的任务执行完毕才会执行当前加入的任务。不能够在新的线程中执行,不具有开辟新的线程能力。
  • 异步任务(async):异步添加到队列当中,无需等待前面的任务执行完成才执行,加入队列就会执行。能够在新的线程中执行,具有开辟新的线程能力。注意:具有开启新线程的能力不表明必定开启新的线程

队列

指执行任务的队列,就是等待执行的任务列表,遵循先进先出IFFO原则。在GCD中有串行队列(Serial Dispatch Queue)并行队列(Concurrent Dispatch Queue),又叫并发队列并发

  • 串行队列(Serial Dispatch Queue):只开启一个线程,每次只有一个任务执行,任务执行完成后才会执行下一个任务。
  • 并行队列(Concurrent Dispatch Queue):可让多个任务同时执行,能够开启多个线程来执行多个任务。注意:并发队列只有在异步函数下才有效

特殊队列

  • 串行主队列:一种串行的主队列,在主队列中调用不能在主线程中再次调用同步任务,不然会形成堵塞,可是能够在其余线程调用同步任务
  • 全局并发队列:一种全局的并发队列

队列与任务的建立

建立队列

  • 建立串行队列
//第一个参数是队列的名字,自定义;第二个参数表示是串行仍是并发
//DISPATCH_QUEUE_SERIAL = NULL,所以DISPATCH_QUEUE_SERIAL能够用NULL代替建立串行队列
dispatch_queue_t queue = dispatch_queue_create("shifx", DISPATCH_QUEUE_SERIAL);
复制代码
  • 建立并发队列
//第一个参数是队列的名字,自定义;第二个参数表示是串行仍是并发
dispatch_queue_t queue = dispatch_queue_create("shifx", DISPATCH_QUEUE_CONCURRENT);
复制代码

任务的建立

  • 建立同步任务
//建立同步任务(queue是队列)
dispatch_sync(queue, ^{
        
});
复制代码
  • 建立异步任务
//建立异步任务(queue是队列)
dispatch_async(queue, ^{
        
});
复制代码

队列与任务总结

综上所述,咱们能够得出一共四种组合外加两种特殊的队列,即异步

  • 串行队列+同步执行
  • 并发队列+同步执行
  • 串行队列+异步执行
  • 并发队列+异步执行
  • 串行主队列
  • 全局并发队列

队列与任务组合使用

串行队列+同步执行

代码实现

-(void)serialSysncText {
    //串行队列
    dispatch_queue_t serial = dispatch_queue_create("shifx", DISPATCH_QUEUE_SERIAL);
    NSLog(@"串行同步任务开始");
    dispatch_sync(serial, ^{
        sleep(1);
        for (int i = 0; i<3; i++) {
            NSLog(@"串行同步任务1 = %d",i);
        }
    });
    dispatch_sync(serial, ^{
        sleep(1);
        for (int i = 0; i<3; i++) {
            NSLog(@"串行同步任务2 = %d",i);
        }
    });
    NSLog(@"串行同步任务结束");
}
复制代码

运行结果

从运行结果当中,咱们能够看到串行队列中的同步任务都是按照前后顺序依次执行的。async

并发队列+同步任务

代码实现

-(void)concurrentAsysncText {
    //并发队列
    dispatch_queue_t concurrent = dispatch_queue_create("shifx", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"并发同步任务开始");
    dispatch_sync(concurrent, ^{
        sleep(1);
        for (int i = 0; i<3; i++) {
            NSLog(@"并发同步任务1 = %d",i);
        }
    });
    dispatch_sync(concurrent, ^{
        sleep(1);
        for (int i = 0; i<3; i++) {
            NSLog(@"并发同步任务2 = %d",i);
        }
    });
    NSLog(@"并发同步任务结束");
}
复制代码

运行结果

从结果得知,并发队列执行的同步任务也是按照顺序依次执行的,由于它们都在主线程中执行的,没有开启新的线程。感兴趣的小伙伴能够打印下线程看下。函数

串行队列+异步执行

代码实现

-(void)serialAsysncText {
    //串行队列
    dispatch_queue_t serial = dispatch_queue_create("shifx", DISPATCH_QUEUE_SERIAL);
    NSLog(@"串行异步任务开始");
    dispatch_async(serial, ^{
        
        for (int i = 0; i<3; i++) {
            sleep(1);
            NSLog(@"串行异步任务1 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(serial, ^{
        for (int i = 0; i<3; i++) {
            sleep(1);
            NSLog(@"串行异步任务2 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    NSLog(@"串行异步任务结束");
}
复制代码

运行结果

从运行结果能够看出,优化

  • 全部的异步任务都是在打印串行异步任务结束后开始执行;
  • 开启了新的线程,但只开启了一个线程;
  • 在串行队列中的异步任务也是按照前后顺序执行。

并发队列+异步执行

代码实现

-(void)concurrentAsysncText {
    //并发队列
    dispatch_queue_t concurrent = dispatch_queue_create("shifx", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"并发异步任务开始");
    dispatch_async(concurrent, ^{
        for (int i = 0; i<3; i++) {
            sleep(1);
            NSLog(@"并发异步任务1 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(concurrent, ^{
        
        for (int i = 0; i<3; i++) {
            sleep(1);
            NSLog(@"并发异步任务2 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    NSLog(@"并发异步任务结束");
}
复制代码

运行结果

从运行结果来看,spa

  • 全部的异步任务都是在打印并发异步任务结束后开始执行;
  • 因为两个异步任务,并发队列开启了两个新的线程
  • 两个异步任务执行没有前后顺序

主队列 + 同步任务

在主线程调用主队列同步任务

因为主队列是串行队列,它不能在主线程中调用主队列同步任务,以下所示崩溃缘由就是同步任务放在了主线程中,须要等待主线程执行完毕才能够,而主线程须要等待该方法执行完成,二者互相等待形成死锁,因此崩溃了。线程

其余线程调用主队列同步任务

代码3d

//使用 NSThread 的 detachNewThreadWithBlock 方法会建立线程
[NSThread detachNewThreadWithBlock:^{
    [self mainSysncText];
}];
    
-(void)mainSysncText {
    NSLog(@"当前所在的线程:%@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_main_queue(), ^{
        for (int i = 0; i<2; i++) {
            sleep(1);
            NSLog(@"主队列同步任务1 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(dispatch_get_main_queue(), ^{
        for (int i = 0; i<2; i++) {
            sleep(1);
            NSLog(@"主队列同步任务2 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
}
复制代码

执行结果

主队列+异步任务

因为主队列是串行队列,因此主队列+异步任务就至关于串行队列+异步任务

代码

-(void)mainAsysncText {
    NSLog(@"当前所在的线程:%@",[NSThread currentThread]);
    NSLog(@"主队列异步任务开始");
    dispatch_async(dispatch_get_main_queue(), ^{
        for (int i = 0; i<2; i++) {
            sleep(1);
            NSLog(@"主队列异步任务1 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        for (int i = 0; i<2; i++) {
            sleep(1);
            NSLog(@"主队列异步任务2 = %d",i);
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        }
    });
    NSLog(@"主队列异步任务结束");
}
复制代码

运行结果

效果等同于串行队列+异步任务

相关文章
相关标签/搜索