对于大型App来说,启动任务多,任务依赖复杂。保障任务逻辑的单一性,解耦启动任务逻辑,合理利用多核CPU优势,提高线程运行效率是重点关注的问题。
所以启动框架核心核心的目的是解决两点:
- 解决任务依赖问题,让单个任务职责更加清晰,代码更加优雅,可以建立启动规范、后续有利于维护。
- 利用多核cpu,提高任务执行效率。
框架调研
解决任务依赖关系类似的框架现在开源的也有好几个。
A. Startup 现阶段只能建立有向无环图,不支持线程调度,网上介绍的文章也很多,了解后是无法真正使用到生产项目中。
B. Alpha 支持有向无环图,线程切换支持不够完美,导致无法支持异步等待,而且长期没有维护。
C. android-startup 支持完美的线程调度,满足基本的需求。
- 但是整体设计稍显复杂和冗余;android-startup中的单个任务不管理图的节点依赖关系,在task manager内直接对任务依赖关系解析,通过
BFS方法获得有向无环图的拓扑排序
,然后将所有的任务丢到线程池内执行,通过任务waitCountDownLatch锁的方式等待前置依赖执行等待和唤醒;Alpha 通过双向链表的方式管理任务,最开始执行头部任务,当任务执行后通知后继节点,后继阶段判断当前依赖是任务是否全部完成来判断是否可以继续执行。
指标 | App Startup | Android Startup | DGAppStartup |
---|---|---|---|
手动配置 | ✅ | ✅ | ✅ |
自动配置 | ✅ | ✅ | ❌ |
依赖支持 | ✅ | ✅ | ✅ |
闭环处理 | ✅ | ✅ | ✅ |
线程控制 | ❌ | ✅ | ✅ |
异步等待 | ❌ | ✅ | ✅ |
依赖回调 | ❌ | ✅ | ✅ |
耗时统计 | ❌ | ✅ | ✅ |
线程优先级 | ❌ | ✅ | ✅ |
多进程 | ❌ | ✅ | ✅ |
依赖关系设计
依赖关系设计上整体都是通过向无环图方式,具体代码实现上参考Alpha
设计。通过后继节点驱动任务运行,避免了拓扑排序等弊端。另外DGAppStartup
未设计通过配置构建任务图,因为考虑配置首先需要解析,然后需要反射调用等。
建立有向无环图
1)类似链表的原理,每个任务节点建立一个后继任务节点的引用集合, 任务执行完成后通知后续节点运行。
2)后继节点将会检查依赖任务是否全部完成,如果全部完成就执行当前任务。
依赖设置
依赖配置这块参考的是官方Startup方式,通过Class对应实例构建有向无环图。
提高任务执行效率
假设场景:ABCD四个任务,都必须在app create阶段执行完。在没有启动框架的情况下,需要把ABCD四个任务放置到主线程串行执行,但是有启动框架后可以通过将ABCD同时异步执行,通过锁等待方式控制四个任务完成后再执行下一步。
代码设计
通过新增isWaitOnMainThread
属性,标记当前任务是否一定需要在这个阶段执行,然后计数所有标记属性的任务,主线程加上锁等待,然后每个任务完成后计算数量减去1,当计数为0的时候释放锁等待,然后主线程继续执行。
总结
该框架已经在过亿的App产品内上线,并已经稳定运行。整体的效果符合预期,单纯拆任务和配合线程调度,整体优化400ms。
框架:Github DGAppStartup
第三篇实战待续...