GCD

作者: HughKaun | 来源:发表于2021-02-28 17:04 被阅读0次

背景

客户端内绝大部分上都是用苹果提供的GCD做异步任务,还有小部分是直接用NSThread或者pthread或者是NSOperation

客户端内GCD使用场景

类别 场景 队列类型 优先级 重要性
子线程IO 读取本地文件、图片缓存 串行
网络请求 并行
数据库操作 串行
旧日志系统所有日志记录(新日志用pthread) 并行
UserDefault 并行
模拟互斥 串行队列顺序访问共享资源 串行
并行队列模拟读写锁 并行
异步转同步 异步任务转同步任务执行 并行
子线程计算 网络回调数据处理 并行
一般数据处理 并行
客户端内所有异步绘制过程 并行
Feed,文章等富文本异步计算布局 并行
子线程视频编解码 并行
消息箱处理socket消息 并行

目前遇到的痛点

  1. 线程爆炸

    • 在没有空闲线程情况下,dispatch_async会创建新线程,造成线程过多
    • 某些循环里会频繁调用GCD去异步执行任务,会瞬间创建很多线程
    • 串行队列在底层是overcommit的,理论在没有空闲线程时,只要是async操作都会创建新线程,如果有很多创建的串行队列,可能会造成线程爆炸
    • 模拟器测试,串行队列最多可以同时创建512个线程,并行队列最多可以同时创建64个线程
  2. 造成死锁

    • dispatch_sync会阻塞当前线程,处理不当会造成死锁
    • GCD的线程池有数量限制,任务密集时会创建不出线程,造成死锁

解决方案

  1. 在GCD任务层级加入数量限制,限制可以异步的任务数量
  2. 引入协程
  3. 加入GCD队列池,限制队列创建,增加队列复用,减少线程数
  4. 修改WBAPM,支持检测长时间执行的block

详细技术方案

  1. GCD机制修改方案

    1.1 创建队列

    • hook dispatch_queue_create -> wb_dispatch_queue_create
    • 对于创建串行队列请求,设置最大队列阈值X (X的值和设备有关,需要进一步测试得出)
      • Y<X,创建标准的isolate串行队列,更新isolate队列计数Y+1
      • Y>=X,新创建的队列会自动target到公用队列
      • 公用队列有一个队列池控制,最多可能有N个队列
      • Y>N,会在N个公用队列中取当前压力最小的一个
      • 监控队列池中每个队列是否销毁,并更新Y-1
      • 自动为每个队列附带一个specific_value,解决之后同队列sync死锁问题
    • 对于创建并行队列,扩展参数枚举值,增加业务相关枚举
      • 对于创建的LOW,DEFAULT,HIGH 优先级的并行队列,直接返回Default_Global_Queue
      • 对于传入的业务相关枚举,根据本地配置,透明的返回对应优先级Global_Queue
      • AyncDraw -> High
      • IO -> Low

    1.2 同步操作sync

    • hook dispatch_sync -> wb_dispatch_sync
    • 判断当前context队列和sync到的队列是否是一个对列,如果是一个队列,直接执行block,不是一个在调用sync

    1.3. 异步操作async

    • 串行队列的async,由于有上面队列池限制,不会线程爆炸
    • 并行队列async
      • 在任务层级添加二级队列,可以设置最大任务阈值,超过阈值任务会在二级队列等待
      • 监控在短时间X内,对相同block的async操作,动态阻塞后续async,并在二级队列等待,另外会记录日志。
hook原dispatch_xxx -> wb_dispatch_xxx
队列api变更
当前串行队列和并行队列原理
image.png
修改后队列池原理
image.png
  1. 尝试引入coobjc协程库(阿里)
  2. WBAPM新增BlockTimeRecorder,记录长时间没执行完的block

具体实现

WBGCDQueueGuard
  1. wb_dispatch_create_queue -> dispatch_create_queue 替换创建队列api
  2. wb_dispatch_set_target_queue -> dispatch_set_target_queue 替换设置target api
  3. wb_dispatch_async1 -> dispatch_async 替换异步dispatch api
  4. wb_dispatch_sync1 -> dispatch_sync 替换同步dispatch api
WBGCDGuardAsyncBucket
  1. 并行队列二级等待Bucket
  2. 遵循标准生产者消费者模型,dispatch_async相当于生产者,有一个线程充当消费者
  3. 消费者最多只能同时执行N个任务
  4. 支持简单负载均衡,比如一个循环,同一个任务短时间多次dispatch_async,会分时执行
WBGCDRootQueue
  1. 管理公共串行队列
  2. 管理公共串行队列的状态,包括被target的数量,公共串行队列的当前压力状态
  3. 每当创建串行队列时,对调用candidate_root_queue接口获取队列
WBGCDGuardConfiguration
  1. 管理GCD Guard的配置
  2. 管理AB状态
  3. 输出一个全局的config
WBGCDGuard_Private
  1. 私有全局变量声明
  2. 私有全局工具方法
私有全局工具方法
/** 
返回queue的类型  
@param 队列   
@return kQueueIsSerial: 串行队列;kQueueIsConcurrent:并行队列    
*/  
int wb_queue_type(dispatch_queue_t queue);  

/** 
返回queue是否已经加入过任务    
@param 队列   
@return 是否  
*/  
BOOL wb_queue_has_post_task(dispatch_queue_t queue);    

/** 
根据QOS返回对应的根队列池  
@param qos_class_t  
@return RootSerialQueuePool 
*/  
RootSerialQueuePool &wb_root_serial_queue_pool(qos_class_t qos);    

/** 
返回queue所对应的根队列  
@param 队列   
@return RootSerialQueue 
*/  
RootSerialQueue *wb_root_serial_queue_with_queue(dispatch_queue_t queue);   

/** 
返回queue是否是全局队列  
*/  
BOOL wb_queue_is_global_queue(dispatch_queue_t queue);  

/** 
返回queue是否是根队列   
*/  
BOOL wb_queue_is_root_serial_queue(dispatch_queue_t queue); 

/** 
返回queue是否是以根队列为target   
*/  
BOOL wb_queue_is_decendant_from_root_queue(dispatch_queue_t queue); 

/** 
返回queue的target queue    98
*/
dispatch_queue_t wb_queue_target_queue(dispatch_queue_t queue); 
dispatch_queue_t wb_dispatch_queue_get_ancestor_target_queue(dispatch_queue_t queue, wb_queue_ancest
or_block block);    

/** 
返回queue的根队列 
*/  
dispatch_queue_t wb_dispatch_queue_get_ancestor_root_target_queue(dispatch_queue_t queue); 

风险及应对

  1. 相同target_queue的队列之前的死锁问题,通过设置specific info解决
  2. 队列复用池数量制定,可以通过大量任务压力测试得出一个阈值
  3. 主线程sync操作可能需要等更久,扫描所有可能的主线程sync,改成用锁机制
  4. 异步任务可能变慢,没有影响,异步任务本来就需要等待

相关文章

  • 多线程之GCD

    GCD介绍 1、GCD简介 2、GCD任务和队列 3、GCD 的基本使用 4、GCD 线程间的通信 5、GCD 的...

  • 扩展GCD(求逆元,解同余方程等等)

    首先要知道gcd函数的基本性质:gcd(a,b)=gcd(b,a)=gcd(|a|,|b|)=gcd(b,a%b)...

  • iOS - GCD

    目录 GCD简介 GCD核心概念 GCD队列的使用 GCD的常见面试题 GCD简介 Grand Central D...

  • iOS-多线程:GCD

    GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(6种不同组合区别) GCD 线程间的通信...

  • 浅析GCD

    GCD目录: 1. GCD简介 为什么要用GCD呢? GCD可用于多核的并行运算GCD会自动利用更多的CPU内核(...

  • 7.3 多线程-GCD

    多线程-GCD 多线程-GCD-串行并行 多线程-GCD.png GCD-线程的通讯、延时操作、定时器 GCD-线...

  • iOS 多线程--GCD

    一、GCD基本介绍 1.GCD简介 GCD是Grand Central Dispatch的缩写,GCD是苹果推出的...

  • 自用算法模板(JAVA版)

    一、数论 1)GCD GCD(求最大公约数) QGCD(快速GCD) extGCD(拓展GCD,解决ax + by...

  • GCD介绍

    一、GCD简单介绍 什么是GCD GCD优势 任务和队列 GCD有2个核心概念 GCD的使用就2个步骤 将任务添加...

  • 7.多线程基础(七)GCD加强

    1.GCD串行队列和并发队列 2.GCD延时执行 3.GCD线程组:(的作用) 4.GCD定时器: GCD的实现 ...

网友评论

      本文标题:GCD

      本文链接:https://www.haomeiwen.com/subject/qngmfltx.html