Android启动优化之多线程依赖线程池

news2024/12/23 13:32:51

背景

开发中会存在多个任务之间互相依赖,运行非常慢的情况,譬如Android在主线程中初始化多个SDK导致App启动慢的情况,搜索一下发现业界的通用做法是构造任务的有向无环图,拓扑排序生成有序的任务列表,然后用线程池执行任务列表(通俗的说就是先找到没有依赖的任务执行,执行完了以后再找到剩下的没有依赖的任务执行,如此反复直到执行完所有任务),但是这个做法无法解决有的任务需要点击对话框授权的情况,基于这个情况打算再造一个轮子出来。

问题

造轮子之前先梳理了一下对这个轮子的要求,发现除了有向无环图外还是有很多细节要解决的。

-依赖任务多线程启动
-支持交互性任务,先拦截任务,交互完成以后再继续执行
-可视化有向无环图
-可视化任务执行情况
-支持多线程、主线程、主进程、第一个任务、最后一个任务等配置属性

方案

开源

TaskGraph: github.com/JonaNorman/…

线程池只能执行没有依赖关系的任务,TaskGraph开源库用有向无环图实现多线程依赖线程池,用拦截器实现交互式任务

图中添加了A任务,B任务依赖A任务执行完再执行,其中A任务需要点击对话框才能执行。

TaskGraph taskGraph = new TaskGraph();
taskGraph.addTask(new Task("A",new Runnable() {//添加A任务
   @Override
   public void run() {
   }
}).addTaskInterceptor(new Task.TaskInterceptor() {
   @Override
   public void onIntercept(Task.TaskInterceptorChain interceptorChain) {//拦截A任务,在A任务之前可以插入对话框
       AlertDialog.Builder builder = new AlertDialog.Builder(TaskGraphModule.getTopActivity());
       builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               interceptorChain.proceed();//继续
           }
       });
       builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               interceptorChain.cancel();//取消
           }
       });
       builder.show();
   }
}));
taskGraph.addTask(new Task("B",new Runnable() {
   @Override
   public void run() {//添加B任务,B任务依赖A任务先完成
   }
}).dependsOn("A").setMainThread(true));
taskGraph.execute();

可视化有向图

搜索TASK_GRAPH_LOG: graphviz:会输出有向图日志,复制到 graphviz-visual-editor 可视化查看

可视化任务执行情况

python systrace.py -o trace.html  -a packagename sched

packagename要替换成运行的app的包名 chrome浏览器打开chrome://tracing/,load 按钮加载trace.html

原理

依赖任务多线程启动

正常的线程池只能执行没有依赖关系的任务,怎么才能让线程池支持运行相互依赖的任务呢? 先找到所有没有进来箭头的节点执行,在该图中也就是A,执行完后删除这个节点和边, 变成了下图

继续以上步骤,找到B运行后删除B,变成下图这样

继续以上步骤,找到C D E同时运行,最终所有任务执行完毕。

把上面的步骤翻译成术语

  • 有箭头的图叫有向图
  • 节点有多少个进来的箭头叫入度
  • 没有进来箭头的节点叫入度为0的节点
  • 箭头没有形成环的图叫有向无环图
  • 依次找到所有入度为0的节点叫拓扑排序

这里有个问题,多线程怎么执行拓扑排序的节点,有两种做法

  1. 拓扑排序的节点列表作为runnable提交到线程池,依赖的任务线程等待其他任务完成在执行
  2. 先把入度为0的所有节点提交到线程池,有一个执行完,就触发寻找剩下入度为0的节点继续执行 两种方案我选了方案2,个人感觉方案2找到的节点执行顺序是最优的,并且不需要线程等待,代码简单而且不需要空占有线程池的线程数量

主要思想:

Grpah图 有多个node节点,每个Node节点有一个Vertex顶点,多个入边edge,多个出边edge, 拓扑排序就是找所有node节点入度为0的边移除然后继续找直到找完所有节点

支持交互性任务

有些任务需要交互输入,完成以后再继续执行,为了实现该功能,可以用拦截器的方式来实现。

拦截器的原理就是调用到拦截器时候会用锁等待,如果执行了proceed方法会唤醒锁然后执行下个拦截器,如果执行了cancel会唤醒锁终止所有任务标记cancel状态,每个拦截器必须调用其中一个方法,要不然会一直等待 核心代码如下

private void nextIntercept() {
    synchronized (sync) {
        currentInterceptor = taskInterceptorQueue.poll();//获取下一个拦截器
        if (currentInterceptor == null) {
            return;
        }
        currentInterceptor.onIntercept(this);//处罚拦截器
    }
    while (!graphController.isFinished()) {
        synchronized (sync) {
            if (cancel) {//调用cancel方法会把cancel赋值为true
                throw new TaskCancelException();
            } else if (currentInterceptor == proceedInterceptor) {//如果调用了proceed会proceedInterceptor赋值为currentInterceptor
                nextIntercept();//执行下一个拦截器
                break;
            } else {
                try {
                    sync.wait();//等待执行proceed或者cancel方法
                } catch (InterruptedException e) {
                }
            }
        }
    }
}

可视化有向无环图

多个依赖任务添加进去以后如果不能可视化成图就会对影响对任务的把控程度,graphviz 是一个图的可视化项目,只要把图的情况写成文本输入就会生成对应图。

  digraph pic {
    A->B;
    B->C;
    }

可视化任务执行情况

多个任务执行实时运行情况,有助于我们优化任务依赖,主要就是在每个任务执行开始调用Trace.beginSection(name),执行完调用Trace.endSection(),然后用命令

python systrace.py -o trace.html  -a packagename sched

生成trace.html,然后用chrome浏览器打开chrome://tracing/点击load按钮加载trace.html就可以查看每个任务的执行情况

支持多线程、主线程、主进程、第一个任务、最后一个任务等配置属性

任务具有多个属性,多线程、主线程、主进程等属性,该实现只要加对应判断就行,第一个任务和最后一个任务则需要遍历所有任务,添加对应依赖关系。

收获

依赖任务多线程调度本身不是很难,在该开源项目中我收获了很多,包括如何实现有向无环图,如何在多线程中实现任务拦截继发,如何使用graphviz实现可视化图,如何用systemtrace可视化任务执行,希望看完文章的同学也可以从中学到什么,谢谢大家的浏览

更多Android 知识点可参考

Android 性能调优系列https://0a.fit/dNHYY

Android 车载学习指南https://0a.fit/jdVoy

Android Framework核心知识点笔记https://0a.fit/acnLL

Android 八大知识体系https://0a.fit/mieWJ

Android 中高级面试题锦https://0a.fit/YXwVq

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[JavaScript] 用电脑计算圆周率评估计算性能

据说全球第一台计算机是在1946年面世的,那它的计算性能是怎样的,至今2022年,发展这么多年,现在的普通计算机性能又是怎样的呢,接下来做一个实验,评估计算性能 文章目录1. 设计2. 编程3. 测试1. 设计 先写一…

[第十三篇]——Docker Compose

Docker Compose Compose 简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。 如果你还不了解…

G1D18-WarshallFloyd课程报告matlab下载

今天先从算法开始吧嘿嘿~ 一、DP (一)Warshall求闭包 1、DP大概看明白啦~ 2、一会再看一下基于邻接表的暴搜 (二)Floyd完全最短路径的Floyd算法 欸嘿~~基本上好啦还差一点图的遍历晚上问问同学吧! 啊哈大概看了一…

BUUCTF·[WUSTCTF2020]大数计算·WP

BUUCTF在线评测 (buuoj.cn) 附件 flag等于 wctf2020{Part1-Part2-Part3-Part4} 每一Part都为数的十六进制形式(不需要0x),并用 - 连接 Part1 2020*2019*2018* ... *3*2*1 的前8位 Part2 520^1314 2333^666 的前8位 Part3 宇宙终极问题的答案 x,y,z绝…

CF461B Appleman and Tree题解

洛谷题面 感觉是非常经典的一道题,最近好像总是见到,今天也算给它做了,发一篇题解来记录一下。 这道题是一道树形 DP 题,设 f[u][0/1]f[u][0/1]f[u][0/1] 表示 uuu 点属于一个无黑点 /// 有且仅有一个黑点的联通块时的方案数。我…

【HDR】Deep high dynamic range imaging of dynamic scenes

文章目录一、贡献二、数据集构建三、算法框架3.1 对齐模块3.2 合成模块3.3 损失函数四、实验一、贡献 Paper: Deep high dynamic range imaging of dynamic scenes Code:https://github.com/TH3CHARLie/deep-high-dynamic-range 首次提出使用机器学习方…

Pdfjs使用

pdfjs使用一、下载二、Springboot引入pdfjs三、利用PDFJS预览pdf文件并加水印四、后端将pdf添加水印参看链接一、下载 pdfjs官方地址 二、Springboot引入pdfjs 针对于pdfjs方面有用的只是pdf这个包下面和viewer.html这个html页面viewer.html是我们用来展示pdf的页面不需要改但…

高压功率放大器在超声悬浮中的应用研究

高压功率放大器的叫法对于不同的人来说是完全不同的,有人叫功率放大器,也有人叫电压放大器,但它们都是指同一个电子测量仪器设备,主要是指内部能够拥有电压和功率放大电路,可以把微弱的外部信号进行放大输出的放大器。…

在华为云 OSC 上快速部署 EMQX MQTT 集群

EMQX Kubernetes Operator 是 EMQ 发布的一个封装、部署和管理工具,也是一个特定的应用控制器,方便 DevOps 人员在 Kubernetes 上编排 EMQX MQTT 消息服务集群,管理其生命周期。 华为云原生基础设施(云容器引擎 CCE、容器镜像服务…

索引数据结构千千万 , 为什么B+Tree独领风骚

索引的由来 大数据时代谁掌握了数据就是掌握了流量,就是掌握的号召力。面对浩瀚的数据如何存储并非难事, 难点在于如何在大数据面前查询依旧快如闪电! 这时候索引就产生了,索引的产生主要还是借鉴于图书管理员书签的功能。在大数…

谷歌、微软、Meta?谁才是 Python 最大的金主?

你知道维护 Python 这个大规模的开源项目,每年需要多少资金吗? 答案是:约 200 万美元! PSF(Python 软件基金会)在 2022 年 6 月发布了 2021 的年度报告,其中披露了以下这份支出明细(…

大家介绍一篇学生选课系统的设计与实现

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

若依框架字典配置以及使用(结合vue和emelent)

一:字典数据创建(我们公司是后端做的,前端不用管) 1.首先新建要指定的默认角色 (1)必须用管理员账号登录才能看到角色管理 (2)具体怎写,可以参考已有的数据&#xff08…

低代码平台中的“模型驱动”与“表单驱动”有何区别?

低代码定义: 低代码是近几年比较火的一种应用程序快速开发方式,它能帮助用户在开发软件的过程中大幅减少手工编码量,并通过可视化组件加速应用程序的高效交付。(低代码的定义来自Forrester报告,被认为是低代码一词的起…

坐标的变换

在QPainter可以使用以下函数变换坐标: QPainter::scale()缩放坐标系统QPainter::rotate()顺时针旋转QPainter::translate()平移QPainter::shear()围绕原点来扭曲坐标系统…

[附源码]java毕业设计小超市进销存管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

fmllr--学习笔记

预备知识: 说话人自适应技术是利用特定说话人数据对说话人无关(Speaker Independent,SI)的码本进行改造,其目的是得到说话人自适应(SPeaker Adapted, SA)的码本来提升识别性能。在某个说话人的训练数据足够多的时候,针对当前说话人数据采用传…

m基于3GPP-LTE通信网络的认知家庭网络Cognitive-femtocell性能matlab仿真

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 本系统所涉及到的几个主要模块,具体有如下几个模块: A. Simulation Flow:仿真流程 B. Initialization:初始化 C. Mobility Model&…

【每日两题】day 01 组队竞赛 删除公共字符

链接:组队竞赛__牛客网 (nowcoder.com) 解题思路 该题目就是求所有队员水平的数组中的尽可能大的水平之和 因为每个队伍都是三个人,平均水平值肯定是排序后水平中间的值 import java.util.*;public class Main {public static void main(String[] ar…

VisualDrag低代码拖拽模板

目录背景技术&文档二开优化方案1. 优化侧边栏2. 优化图片插入3. 新增可插入画布的组件4. 解决组件鼠标默认事件冲突的问题数据保存对接&页面生成预览保存对接生成预览源码下载背景 接到一个需求做一个拖拽模板低代码生成界面(如上图)&#xff0c…