场景构造
用swiftui写6个一摸一样的helloworld程序,间隔1s刷新展示一个不断递增的数字。分别将6个应用至于前台焦点(App_Foreground)、前台非焦点完全可见(App_Complete_Visiable)、半遮挡(App_Partially_Visiable)、被完全遮挡(App_Unvisiable)、最小化(App_Minimize)、隐藏(App_Hide)。如图所示,然后用instruments抓一段10s左右的trace:
注:隐藏应用指通过右键Dock栏点击隐藏这个动作。最小化即点击窗口左上角的最小化小圆圈。
优先级分布情况
打开每个进程观察它的Context Switch Points
视图,里面可以看到每次线程上下文调度的优先级,依次对不同的可见状态下的应用进行分析。
注: 线程状态有好多种:Running、Runnable、Blocked等,这里先研究运行态的优先级和是否可见的关联关系,后文如果没有特殊说明,优先级的变化均指Running态的变化。
进程内的线程优先级的策略异同
这个简单的demo进程中包含很多个线程,不同的线程的优先级分布也是不一样的,各个进程包含的线程名及其个数罗列如下,可以看到,每个应用都有一个主线程、事件处理线程、workloop
线程, 另外有n个start_wqthread
线程,这个线程的用处暂无进一步进行研究:
线程名 | App_Foreground | App_Complete_Visiable | App_Partially_Visiable | App_Unvisiable | App_Minimize | App_Hide |
---|---|---|---|---|---|---|
Main Thread(UI线程) | 1 | 1 | 1 | 1 | 1 | 1 |
com.apple.NSEventThread (事件处理) | 1 | 1 | 1 | 1 | 1 | 1 |
dispatch_workloop_worker_thread(猜测定时器) | 1 | 1 | 1 | 1 | 1 | 1 |
start_wqthread | 4 | 2 | 3 | 2 | 2 | 2 |
以进程名命名的线程 | 1 | 1 | 1 | 1 | 1 | 1 |
线程切换running总次数和执行时间查看方法:
MainThread
优先级比较
应用 | 优先级变化趋势 | 线程切换running总次数 | 总执行时间(ns) |
---|---|---|---|
App_Foreground | trace记录中一开始主线程优先级为46,焦点点击到主线程后优先级变为稳定的47 | 4160 | 379980 |
App_Complete_Visiable | 稳定46 | 960 | 92880 |
App_Partially_Visiable | 稳定46 | 990 | 92790 |
App_Unvisiable | 大部分优先级为4,少部分优先级为46 | 625 | 36460 |
App_Minimize | 大部分优先级为4,少部分优先级为46 | 382 | 41740 |
App_Hide | 大部分优先级为4,少部分优先级为46 | 283 | 38950 |
前台焦点进程的优先级变化趋势图(3.524s左右切换为焦点应用):
不可见进程的优先级变化趋势图:
com.apple.NSEventThread
线程的优先级比较
应用 | 优先级变化趋势 | 线程切换running总次数 | 总执行时间(ns) |
---|---|---|---|
App_Foreground | 一开始线程优先级为46,切换为焦点后优先级变为稳定的47 | 4512 | 152360 |
App_Complete_Visiable | 稳定46 | 692 | 27140 |
App_Partially_Visiable | 稳定46 | 888 | 26750 |
App_Unvisiable | 稳定46 | 12 | 274 |
App_Minimize | 稳定46 | 4 | 203 |
App_Hide | 稳定46 | 5 | 294 |
dispatch_workloop_worker_thread
线程的优先级比较
应用 | 优先级变化趋势 | 线程切换running总次数 | 总执行时间(ns) |
---|---|---|---|
App_Foreground | 3%的46, 94%的37,2%的31 | 298 | 6050 |
App_Complete_Visiable | 1次46,99%为37 | 63 | 2550 |
App_Partially_Visiable | 12%的46, 52%的37,36%的31 | 26 | 1460 |
App_Unvisiable | 4%的46, 96%的4 | 50 | 1600 |
App_Minimize | 30%的46,70%的4 | 10 | 441 |
App_Hide | 50%的46,50%的4 | 10 | 271 |
start_wqthread
线程的优先级比较
应用 | 优先级变化趋势 | 线程切换running总次数 | 总执行时间(ns) |
---|---|---|---|
App_Foreground | 大部分37 | 1809 | 27622 |
App_Complete_Visiable | 大部分37 | 233 | 4727 |
App_Partially_Visiable | 大部分46,少部分37 | 21 | 611 |
App_Unvisiable | 大部分46,1次4 | 6 | 145 |
App_Minimize | 大部分46,少部分37 | 56 | 1170 |
App_Hide | 大部分37、46,几次31 | 59 | 1363 |
明确的结论
这里的结论,前提是轻载,没有特意加压观察:
- 焦点进程的主线程的优先级为47,非焦点可见进程(包括半遮挡)的主线程的优先级为46。不可见进程的主线程优先级会降低,大部分时间为最低的优先级4。
- 焦点进程的事件处理线程的优先级为47, 其余进程的事件处理线程的优先级为46,均保持较高的优先级
workloop
线程和start_wqthread
线程(代表业务逻辑)大部分优先级低于UI和事件处理线程- 前台可见的进程执行的逻辑更多,运行时间更长,不可见和最小化进程包括UI、事件处理、业务逻辑都很少(Nap?)
遗留问题
- 应用的线程模型的进一步研究,如workloop线程到底是不是定时器线程,start_wqthread线程的主要工作内容、以进程名字命名的线程名的主要功能等。
- 线程状态的进一步研究,如Running、Runnable、Blocked的状态机模型是什么样的,网上没有找到对应的资料。
- 重载下的线程优先级是否相比轻载会发生变化。
- 可见应用除了优先级的区别,和大小核是否也有关联关系。
- 不可见应用执行逻辑更少,是因为NAP机制?但是定时器的数字和前台基本一致。