GCD为Grand Central Dispatch的缩写,是Apple开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统,是一个在线程池模式的基础上执行的并行任务。
GCD是一个替代诸如NSThread等技术的很高效和强大的技术。GCD完全可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题。GCD的工作原理是让一个程序,根据可用的处理资源,安排他们在任何可用的处理器核心上平行排队执行特定的任务。这个任务可以是一个功能或者一个程序段。下面,我们就通过一些实例来演示一下GCD的相关知识。
一、GCD的基本概念
在正式开始编写代码之前,我们先来简单了解一下和GCD相关的两个概念:任务和队列。任务是指要执行什么操作;队列是用来存放要执行的任务。也就是说,要使用GCD,首先要指定任务,确定自己想做什么,然后再将任务添加到队列中。一旦这两项工作准备就绪,GCD会自动将队列中的任务取出,将其放到对应的线程中去执行。并且,任务的取出遵循队列的FIFO原则,即先进先出,后进后出。
GCD中有两个用来执行任务常用的函数:dispatch_sync(dispatch_queue_t queue, dispatch_block_t block)和dispatch_async(dispatch_queue_t queue, dispatch_block_t block)。其中,参数queue表示队列,参数block表示要执行的任务(即将要执行的任务放到block代码块中)。前一个函数表示用同步的方式去执行任务,后面一个函数表示用异步的方式去执行任务。同步执行和异步执行的区别在于:同步执行时,任务只能在当前线程中执行,不具备开启新线程的能力;而异步执行可以开启新线程,并且是将任务放在新开的线程中去执行。
关于队列需要补充一点,在GCD中,队列可分为并发队列(Concurrent Dispatch Queue)和串行队列(Serial Dispatch Queue)。其中,并发队列可以让多个任务并发的执行,即自动开启多个线程同时执行任务,它只在异步函数下才有效。而串行队列只能让多个任务一个接一个的去执行。
关于上面提到的同步函数和异步函数,以及并发队列和串行队列,它们之间的联系和区别总结如下:
1、同步函数和异步函数的主要区别在于:能不能开启新的线程。其中,同步函数只能在当前线程中执行任务,不具备开启新线程的能力;而异步函数可以在新的线程中执行任务,具备开启新线程的能力;
2、并发队列和串行队列的主要区别在于:任务的执行方式。并发队列允许多个任务并发的执行,并且它只能在异步函数中有效;而在串行队列中,一个任务执行完毕后,下一个任务才会被执行。
二、GCD的基本使用
新建一个工程,在ViewController中实现- touchesBegan: withEvent:方法,然后再来看一下异步函数和并发队列、异步函数和串行队列,以及同步函数和并发队列、同步函数和串行队列这几种组合情况下程序运行的效果。
GCD的使用步骤是:先创建一个队列,然后再定制任务,并将这个任务添加到队列中去。创建队列时,使用dispatch_queue_create( )函数,它的返回值是一个dispatch_queue_t类型。dispatch_queue_create( )函数有两个参数,第一个参数是一个C语言字符串,它是用来标识不同的队列,可以理解为给队列取名字,可以为空;第二个参数是一个宏,用来标识所创建这个队列的属性,其取值一般为DISPATCH_QUEUE_CONCURRENT(并发队列),或者DISPATCH_QUEUE_SERIAL(串行队列)。队列创建完毕之后,根据任务需要来决定使用dispatch_async( )函数或者dispatch_sync( )函数。前面一个函数表示异步函数,后面一个函数表示同步函数。
1、异步函数和并发队列
先来看一下异步函数和并发队列的使用情况。首先使用dispatch_queue_create( )函数创建一个并发队列,然后再用dispatch_async( )函数来封装任务,为了便于对比查看,我们在一个队列中添加了3个任务,并且在适当的位置加入了打印信息:
// MARK:- 点击屏幕执行代码
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 点击屏幕以后执行异步函数和并发队列
[self asyncFuncAndConcurrentQ];
}
// MARK:- 异步函数和并发队列
- (void)asyncFuncAndConcurrentQ {
// 创建一个并发队列
dispatch_queue_t queue = dispatch_queue_create("lable", DISPATCH_QUEUE_CONCURRENT);
/**
* dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t _Nullable attr#>)
* 第一个参数 : 它是一个C语言的字符串儿,可以为空。它是一个标签,用来区分不同的队列;
* 第二个参数 : 它是用来描述队列类型的信息,一般为DISPATCH_QUEUE_CONCURRENT(并发队列)或者DISPATCH_QUEUE_SERIAL(串行队列)。
*/
NSLog(@"start------%s", __func__);
// 定制任务,并将其添加到队列中(一个队列中可以添加多个任务)
dispatch_async(queue, ^{
// 要执行的任务
NSLog(@"线程1:%@", [NSThread currentThread]);
});
/**
* dispatch_async(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
* 第一个参数 : 用于接收队列,也就是要把上面创建的队列传进来;
* 第二个参数 : 它是一段block代码,用来封装你要执行的代码。
*/
dispatch_async(queue, ^{
// 要执行的任务
NSLog(@"线程2:%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 要执行的任务
NSLog(@"线程3:%@