前言
先说说GCD多线程中的进程和线程
进程:进程就是一段程序的执行过程,在操作系统中,进程既是基本的分配单元,也是基本的执行单元。进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
线程: 通常在一个进程中可以包含若干个线程,一个进程中至少有一个线程,也是线程的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
DispatchQueue
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
// 创建一个队列,第一个参数字符串唯一标识,第二个参数串行或并行,也可以是自定义dispatch_queue_attr_t
dispatch_queue_attr_make_with_autorelease_frequency
// 返回一个属性,指定调度队列如何管理它执行的块的自动释放池。
OS_dispatch_queue_main
// 系统提供的调度队列,用于在应用程序的主线程上调度串行执行的任务。
OS_dispatch_queue_global
// 系统提供的调度队列,用于调度并发执行的任务。
OS_dispatch_queue_serial
// 一个自定义调度队列,用于调度任意线程上的串行执行任务。
OS_dispatch_queue_concurrent
// 一个自定义调度队列,用于调度并发执行的任务。
dispatch_queue_main_t
typedef NSObject<OS_dispatch_queue_main> *dispatch_queue_main_t;
// 一个调度队列,绑定到应用程序的主线程并在该线程上串行执行任务。
dispatch_queue_global_t
dispatch_queue_global_t dispatch_get_global_queue(long identifier, unsigned long flags);
// 使用全局线程池中的线程并发执行任务的调度队列。
dispatch_queue_serial_t
// 一个调度队列,以先进先出(FIFO)顺序串行执行任务。
dispatch_queue_concurrent_t
// 一个调度队列,以任何顺序同时执行任务,跳过可能存在的任何障碍。
dispatch_release(dispatch_object_t object);
// mrc下减少调度对象的引用计数(保留计数)
dispatch_retain(dispatch_object_t object);
// mrc下增加调度对象的引用计数(保留计数)
dispatch_set_finalizer_f(dispatch_object_t object, dispatch_function_t finalizer);
// 设置调度对象的终结器函数。
dispatch _queue _attr _t
描述调度队列行为的属性。
主线程或后台线程上串行队列(DISPATCH_QUEUE_SERIAL)和并行队列(DISPATCH_QUEUE_CONCURRENT)管理任务执行的对象,也就是线程队列,采用FIFO(先进先出)的模式,以块的形式提交到线程池中进行任务。
- 注意:尝试在主队列上同步执行工作项会导致死锁。
提交到串行队列的块按FIFO顺序一次执行一个。但是,请注意,提交给独立队列的块可以相互同时执行。提交到并发队列的块以FIFO顺序出列,但如果有资源可以同时运行。
如果您的应用未使用ARC,则应在不再需要时调用调度队列。提交到队列的任何挂起块都会保留对该队列的引用,因此在完成所有挂起块之前不会释放队列。
在设计并发执行任务时,不要调用阻塞当前执行线程的方法。当并发调度队列调度的任务阻塞线程时,系统会创建其他线程来运行其他排队的并发任务。如果任务阻塞太多,系统可能会耗尽您应用的线程。
应用程序消耗太多线程的另一种方法是创建太多私有并发调度队列。由于每个调度队列都占用线程资源,因此创建其他并发调度队列会加剧线程消耗问题。不是创建专用并发队列,而是将任务提交给其中一个全局并发调度队列。对于串行任务,请将串行队列的目标设置为其中一个全局并发队列。这样,您可以维护队列的序列化行为,同时最小化创建线程的单独队列的数量。
1、创建队列:
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
用来创建一个队列,创建的方式,通常是由串行和并行两种形式
- 串行(DISPATCH_QUEUE_SERIAL)
- 并行(DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t queue = dispatch_queue_create("com.queue", DISPATCH_QUEUE_SERIAL);
但是创建的方式不一定
2、主队列:
主队列是由系统自动分配创建的,并与主线程关联,属于串行队列。获取主队列方式dispatch_get_main_queue
dispatch_async(dispatch_get_main_queue(), ^{
changeDat();
});
主动去执行被添加到main_queue的任务task(也就是说我们可以主动来调用添加到主线程队列的block)阻塞主线程去执行其他线程。
dispatch_main()、UIApplicationMain 、CFRunLoopRun()
这三个方法在应用程序中有且只能有一个,用于阻塞主线程,执行其他线程
3、全局队列:
全局队列是并发性队列,获取全局队列的方式
dispatch_get_global_queue(, 0);
其中第一个参数是优先级:
DISPATCH_QUEUE_PRIORITY_HIGH // 高
DISPATCH_QUEUE_PRIORITY_DEFAULT // 默认
DISPATCH_QUEUE_PRIORITY_LOW // 低
DISPATCH_QUEUE_PRIORITY_BACKGROUND // 后台
使用的方式
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4、QOS(服务质量)的配置
在iOS8以后,通过QOS配置队列,使用枚举qos_class_t的值,提供了更高的全局任务队列。
系统使用这些意图来确定在可用资源的情况下执行任务的最佳方式。例如,系统为包含用户交互任务的线程提供更高的优先级,以确保快速执行这些任务。相反,它为后台任务提供较低的优先级,并可能尝试通过在更节能的CPU内核上执行它们来节省功耗。系统根据系统条件和您安排的任务确定如何动态执行任务。比如用户界面刷新,网络请求,资源下载,缓存存取之类的
QOS可以用于dispatch_queue, NSOperation, NSOperationQueue, NSThread ,pthreads中
优先级由上到下
QOS_CLASS_USER_INTERACTIVE
//必须及时执行,用于用户交互式任务,例如动画,事件处理或更新主线程界面。
QOS_CLASS_USER_INITIATED
// 需要很快完成工作,用于阻止用户主动使用您的应用的任务。
QOS_CLASS_DEFAULT
// 默认级别。
QOS_CLASS_UTILITY
// 不需要及时响应,比如下载,但是用户可以看到正在工作。
QOS_CLASS_BACKGROUND
// 不需要及时响应,且在后台,用户不知道进度,您创建的维护或清理任务例如:后台下载
QOS_CLASS_UNSPECIFIED
// 最低其他等级,开发人员没有指定,系统根据情况进行选定QOS等级
QOS配置的对应的OC类
NSQualityOfServiceUserInteractive
NSQualityOfServiceUserInitiated
NSQualityOfServiceUtility
NSQualityOfServiceBackground
使用的方式与上面相同,更改优先级:
dispatch_queue_t globalQueue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);
该函数的返回值上使用dispatch_resume、dispatch_suspend无效,在dispatch_queue中,如果我们想要指定QOS的等级的话,我们可以使用函数dispatch_queue_attr_make_with_qos_class。
dispatch_queue_attr_t qos = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INTERACTIVE, 0);
dispatch_queue_t queue = dispatch_queue_create("com.qos", qos);
// 其他使用,获取到QOS类
dispatch_qos_class_t qos_class = dispatch_queue_get_qos_class(queue, 0);
/// 用于 根据已知队列来获取同qos等级的全局任务队列
dispatch_get_global_queue(dispatch_queue_get_qos_class(the_queue, nil), 0);
/// 或根据已知的全局任务队列来创建与其qos相等的任务队列
dispatch_queue_t the_global = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
dispatch_queue_t the_queue = dispatch_queue_create("com.example.gcd", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, dispatch_queue_get_qos_class(the_global, 0), 0));
// 或者对QOS设置block等级
dispatch_block_t the_block = dispatch_block_create_with_qos_class(0, QOS_CLASS_UTILITY, -8, ^{
});
dispatch_async(queue, the_block);
//dispatch_sync, dispatch_after等等需要用到dispatch_block的地方
两种枚举的对比方式:

网友评论