一、概览
二、ArkTS高性能编程
-
ArkTS高性能编程规则
更有利于方舟编译运行时,进行编译优化,生产更高性能的机器码,保障程序运行得更快
-
出于代码的稳定性和性能考虑,一些TypeScript的特性被限制了。比如需要不支持属性的动态变更、变量或参数需要有明确的类型声明和返回值生命等
-
不支特使用any和unknown 请使用明确类型,或者使用联合类型、泛型或者object替代any,必须使用any的场景可以使用ESobject代替,但是可能存在性能问题,谨慎使用。
-
-
使用AOT模式对应用进行编译优化
方舟编译运行通过采用PGO(配置文件引导型优化)方式,提前生成高性能机器码,从而提升程序运行速度
AOT模式即提前编译,能够在Host端将字节码提前编译成Target端可运行的机器码,这样字节码可以获得充分编译优化,放到Target端运行时可以获得加速
官方文档开启AOT模式https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-hvigor-aot-V5
三、提升应用启动和响应速度
-
冷启动过程简介
应用启动时,后台无该应用的进程,需要创建新的进程,这种启动方式叫做冷启动。
过程大概分为四个阶段:应用进程创建和初始化、App和Ability的初始化、Ability生命周期、加载绘制首页
-
第一阶段:应用需要在它的进程孵化仓里面去孵化出一个新的进程,进行必须的一些资源和初始化
优化:设置合适分辨率的startWindowIcon(启动图标)
-
第二阶段:Application是应用独有的一个上下文,包含了所有应用侧相关的一些生命周期,ability是应用启动了Application之后进行创建的一个具体的组件,ability也会在初始化过程中创建必须的上下文和资源
优化:减少首页Abiltiy或者Page中import的模块
-
第三阶段:Abiltiy的生命周期
优化:使用异步加载
-
第四阶段:加载绘制首页
优化:延迟加载
-
-
使用异步加载
使用异步加载可以在后台线程中处理耗时操作,从而提升响应速度
-
延迟加载
将不必要的资源延迟加载可以减少应用的启动时间。使用List、Grid、Swiper等容器组件时,配合系统提供的LazyForEach数据懒加载能力,可以有效减少应用启动时间和内存占用
-
使用缓存
选择合适的缓存策略可以提高应用程序的性能和响应速度,从而提升应用响应速度,使用LazyForEach时,可以搭配使用cachedCount方法,自定义控制列表的缓存数量,默认加载1条缓存数量
四、减少丢帧卡帧
-
避免在主线程上执行耗时操作
UI主线程是HarmonyOS应用中最重要的线程之一,在主线程上执行耗时操作会堵塞UI渲染,从而导致UI主线程的负载过高。因此,可以将耗时操作放在TaskPool或Worker等后台线程中执行
-
Worker和TaskPool对比
实现 TASKPOOL WORKER 内存模型 线程间隔离,内存不共享。 线程间隔离,内存不共享。 参数传递机制 采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。支持ArrayBuffer转移和SharedArrayBuffer共享。 采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。支持ArrayBuffer转移和SharedArrayBuffer共享。 参数传递 直接传递,无需封装,默认进行transfer。 消息对象唯一参数,需要自己封装。 方法调用 直接将方法传入调用。 在Worker线程中进行消息解析并调用对应方法。 返回值 异步调用后默认返回。 主动发送消息,需在onmessage解析赋值。 生命周期 TaskPool自行管理生命周期,无需关心任务负载高低。 开发者自行管理Worker的数量及生命周期。 任务池个数上限 自动管理,无需配置。 同个进程下,最多支持同时开启64个Worker线程,实际数量由进程内存决定。 任务执行时长上限 3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时),长时任务无执行时长上限。 无限制。 设置任务的优先级 支持配置任务优先级。 不支持。 执行任务的取消 支持取消已经发起的任务。 不支持。 线程复用 支持。 不支持。 任务延时执行 支持。 不支持。 设置任务依赖关系 支持。 不支持。 串行队列 支持。 不支持。 任务组 支持。 不支持。 -
适用场景对比:由于TaskPool的工作线程会绑定系统的调度优先级,并且支持负载均衡(自动扩缩容),而Worker需要开发者自行创建,存在创建耗时以及不支持设置调度优先级,故在性能方面使用TaskPool会优于Worker,因此大多数场景推荐使用TaskPool。
-
常见的一些开发场景及适用具体说明如下:
-
运行时间超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时)的任务。例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker。
-
有关联的一系列同步任务。例如在一些需要创建、使用句柄的场景中,句柄创建每次都是不同的,该句柄需永久保存,保证使用该句柄进行操作,需要使用Worker。
-
需要设置优先级的任务。例如图库直方图绘制场景,后台计算的直方图数据会用于前台界面的显示,影响用户体验,需要高优先级处理,需要使用TaskPool。
-
需要频繁取消的任务。例如图库大图浏览场景,为提升体验,会同时缓存当前图片左右侧各2张图片,往一侧滑动跳到下一张图片时,要取消另一侧的一个缓存任务,需要使用TaskPool。
-
大量或者调度点较分散的任务。例如大型应用的多个模块包含多个耗时任务,不方便使用Worker去做负载管理,推荐采用TaskPool。
-
-
减少渲染进程的冗余开销
使用资源图代替绘制、合理使用renderGroup、尺寸位置设置尽量使用整数,可以减少渲染所需要的时间,从而减少丢帧卡顿
-
animateTo需要判断初始状态和结束状态两个状态,需要进行两次更新
-
transition只需要去判断初始状态或者时结束状态的最总结果,只需要一次判断,因此性能更好
-
-
合理使用RenderGroup
对于没有状态变量绑定的一些组件去做属性动画时,可以加上renderGroup属性,加速动画效果。前提是组件的内容不会发生变化,否则缓存信息会失效。 -
减少视图嵌套层级
应用开发中的用户界面(UI)布局是用户与应用程序交互的关键部分。不合理的布局越多,视图的创建、布局、渲染等流程所需的时间就越长。因此,减少嵌套层次或者使用高性能布局节点,可以减少丢帧卡顿。
-
组件复用配合LazyForEach(可以去看我之前的瀑布流案例)
使用ArkUI开发范式提供的组件复用机制,通过重复利用已经创建过并缓存的组件对象,降低组件短时间内频繁创建和销毁的开销,提升组件的加载效率,降低UI线程负载,从而减少丢帧卡顿
-
精确控制状态变量的关联组件数
@State等状态变量关联组件越多,状态数据变更时刷新的组件越多,UI线程负载越重,因此移除冗余的组件关联可以减少丢帧卡顿
-
在对象上谨慎使用状态变量关联
使用@Prop会进行数据的拷贝,而@ObjectLink只是将引用指向原数据
更多可参考华为开发者学堂