首页 » 漏洞 » GCD学习笔记

GCD学习笔记

 

概述

本文用来记录使用 GCD 多线程中的体会,以及记录阅读优秀第三方代码使用 GCD 的心得

QoS

The following Quality of Service (QoS) classifications are used to indicate to the system the nature and importance of work. They are used by the system to manage a variety of resources. Higher QoS classes receive more resources than lower ones during resource contention

QoSiOS8 之后苹果推出的一套机制,用来修饰多线程派发任务的性质和重要性, GCD 会根据这些性质决定执行任务的时候获取的资源量。 QoS 提供了五种不同的任务性质枚举变量,分别是:

  • NSQualityOfServiceUserInteractive

    表示用户交互任务,任务优先级高

  • NSQualityOfServiceUserInitiated

    用户发起的需要立即得到回应的任务,优先级高

  • NSQualityOfServiceUtility

    不需要立刻返回结果的任务,执行时间稍长。比如下载图片,数据请求

  • NSQualityOfServiceBackground

    后台任务,对用户不可见,比如数据备份。任务的时间比较长

  • NSQualityOfServiceDefault

    默认优先级任务,处于 UserInitiatedUtility 之间

通过 dispatch_queue_attr_make_with_qos_class 获取线程任务属性,然后用来配置创建的线程:

dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0); return dispatch_queue_create("sindrilin.com.user_interactive", attr);

并发队列

通过函数 dispatch_get_global_queue 获取到的是并发队列,因此我们并不知道这个队列中的线程数是多少。换句话说,如果派发任务到并发队列中,如果执行大量耗时操作导致线程被锁住的时候, GCD 可能会创建新线程来继续执行任务,这样等待的线程越多,新建的线程也就越来越多。每个线程拥有自己的栈信息,需要分配一定的内核内存和应用内存的空间,具体消耗参照下表

类型 消耗估算 详情
内核结构体 1KB 存储线程数据结构和属性
栈空间 子线程(512KB)
Mac主线程(8MB)
iOS主线程(1MB)
堆栈大小必须为4KB的倍数
子线程的最小内存为16KB
创建时间 90微秒 1G内存
Intel 2GHz CPU
Mac OS X v10.5

如果遇到大量的耗时派发任务,直接使用并发队列可能会造成 CPU 过大的负荷。参照 YYKit 的做法,对 QoS 每一个优先级创建一个静态的结构体。每个结构体存储着等同于 CPU 激活核心数的串行队列,然后派发任务的时候轮询队列执行

GCD学习笔记

这种做法让线程最大化的得到复用,以及控制了线程数量。另外使用结构体也是 YYKit 的统一做法了,尽可能减少了继承带来的内存损耗。这是仿写代码的结构体创建核心部分:

typedef struct __LXDDispatchContext {     const char * name;     void ** queues;     uint32_t queueCount;     int32_t offset; } *DispatchContext, LXDDispatchContext;  LXD_INLINE DispatchContext __LXDDispatchContextCreate(const char * name,                                                   uint32_t queueCount,                                                   LXDQualityOfService qos) {      DispatchContext context = calloc(1, sizeof(LXDDispatchContext));     if (context == NULL) { return NULL; }      context->queues = calloc(queueCount, sizeof(void *));     if (context->queues == NULL) {         free(context);         return NULL;     }     for (int idx = 0; idx < queueCount; idx++) {         context->queues[idx] = (__bridge_retained void *)__LXDQualityOfServiceToDispatchQueue(qos, name);     }     context->queueCount = queueCount;     if (name) {         context->name = strdup(name);     }     context->offset = 0;     return context; }

原文链接:GCD学习笔记,转载请注明来源!

0