YBTaskScheduler 研究
ChenghuiBai Lv3

学习
YBTaskScheduler

iOS 任务调度器:为 CPU 和内存减负

[TOC]

作用

可能遇到的问题

当主线程执行大量的任务会造成卡顿,应该把这些任务移动到子线程异步执行。

但是异步执行的任务量过大,会导致cpu和内存占用率过高,然后引发一系列其他问题。

解决思路
延时降频

降低任务执行频率,或延缓任务执行时机,以时间换空间。

淘汰

淘汰不必要执行的任务,如已经滑出屏幕的ui异步绘制任务就可以移除,只保留需要显示屏幕可见部分的绘制任务。

优先级调度

个人理解这个对降低cpu、内存占用率高没什么作用,允许设置优先级应该是一个附加功能,真正起到作用的是使用runloop起到降频(任务到runloop空闲时才执行)的作用。

原理和实现

原理

YBTaskScheduler 监听runloop的状态,只有在runloop将要进入空闲状态时才执行任务。

设置任务最大数量,在添加任务的时候将超过最大限制的任务淘汰。

实现
命令模式 + runloop

想要管理这些复杂的任务,并且在合适的时机调用它们,自然而然的就想到了命令模式。意味着任务不能直接执行,而是把任务作为一个命令装入容器。

在 Objective-C 中,显然 Block 代码块能解决延迟执行这个问题:

[_scheduler addTask:^{
/*
具体任务代码
解压图片、裁剪图片、访问磁盘等
*/
}];

然后组件将这些代码块“装起来”,组件由此“掌握”了所有的任务,可以自由的决定何时调用这些代码块,何时对某些代码块进行淘汰,还可以实现优先级调度。

既然是命令模式,还差一个 Invoker (调用程序),即何时去触发这些任务。结合 iOS 的技术特点,可以监听 RunLoop 循环周期来实现:

static void addRunLoopObserver() {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
taskSchedulers = [NSHashTable weakObjectsHashTable];
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopBeforeWaiting | kCFRunLoopExit, true, 0xFFFFFF, runLoopObserverCallBack, NULL);
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
CFRelease(observer);
});
}

然后在回调函数中进行任务的调度。

策略模式

d4d2cc7e6fc6db790b737872f1549666.png

具体策略:

栈:后加入的任务先执行(可以理解为后加入的任务优先级高),优先淘汰先加入的任务。

队列:先加入的任务先执行(可以理解为先加入的任务优先级高),优先淘汰后加入的任务。

优先队列:自定义任务优先级,不支持任务淘汰。

数据结构

为了实现淘汰策略和优先级调度,作者直接使用了 C++ 的数据结构:deque 和priority_queue。

要实现任务淘汰,所以使用 deque 双端队列来模拟栈和队列,而不是直接使用 stack 和 queue。

使用 priority_queue 优先队列来处理自定义的优先级调度,它的缺点是不能删除低优先级节点,为了节约时间成本姑且够用。

线程安全

任务的调度可能在任意线程,所以必须要做好容器(栈、队列、优先队列)访问的线程安全问题,组件是使用 pthread_mutex_t 和 dispatch_once 来保证线程安全,同时笔者尽量减少临界区来提高性能。

值得注意的是,如果不会存在线程安全的代码就不要去加锁了。

亮点

设计模式

使用策略模式区分不同淘汰策略,以及任务优先级设置。

使用命令模式,将任务添加和任务调度隔离。可以自由的决定何时调用这些代码块,何时对某些代码块进行淘汰,还可以实现优先级调度。

Runloop

监听runloop回调状态

将任务放在runloop空闲状态才下执行,避免任务集中执行,起到延缓作用。

数据结构

使用了 C++ 的数据结构:deque 和priority_queue。

使用 deque 双端队列来模拟栈和队列。

使用 priority_queue 优先队列来处理自定义的优先级调度。

  • Post title:YBTaskScheduler 研究
  • Post author:ChenghuiBai
  • Create time:2019-06-06 20:11:26
  • Post link:https://baichenghui.github.io/2019/06/06/YBTaskScheduler-研究/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.