
#2023盲盒+码# 通过案例介绍如何使用AOT 原创
【本文正在参加 2023「盲盒」+码有奖征文活动】,活动链接 https://ost.51cto.com/posts/25284
通过案例介绍如何使用AOT
工程准备
-
打开 ArkTS 工程,同步完成。
-
将工程编译模式调整为 release,并关闭混淆功能。
- 将工程编译模式调整为 release
通过
build
窗口进行编译构建时,默认Build Hap(s)
为 debug 编译模式,Build App(s)
为 release 编译模式。开发者也可以自主选择编译模式为 debug 或 release。
通过 DevEco Studio 中下图方式,选择调整
Build Hap(s)
为 release 编译模式。-
关闭混淆功能
在模块级 build-profile.json5 文件中,配置 buildOption 内的字段。
{ "apiType": 'stageMode', "buildOption": { "arkOptions": { "apPath": "./modules.ap", "obfuscation": { "ruleOptions": { "enable": false } } }, ... }
-
获取 ap 文件:
a. 打开生成 ap 文件的开关:
hdc shell param set ark.profile true
b. 将步骤2中release 模式打包出 HAP 运行在真机上,在需要优化的场景进行操作,从而记录高频操作。
c. 操作结束后,真机里记录的 ap 文件即可放入应用 AOT 编译使用的目录,通过命令行来获取 ap 文件:
hdc file recv /data/local/ark-profile/100/{bundle_name}/modules.ap {apPath}
- {bundle_name}: 表示包名。
- {apPath}: 表示 buildOption 设置的 apPath 参数对应的路径。
d. 若设备不再需要获取 ap 文件,可以通过下面两个方法关闭:
- hdc shell param set ark.profile false
- 设备重启
应用代码变化或常用操作变化时,建议重复以上步骤更新 ap 文件。
-
从真机中获取 ap 文件,将 ap 文件放入第2步中指定的apPath路径。
-
开启端侧安装时编译后,再次启动 release 模式进行编译,并安装。
hdc shell param set persist.bm.install.arkopt partial
-
在等待应用安装,且端侧编译优化完成后,应用运行性能即可得到相应的提升。
可以通过如下方式确认端侧编译是否结束
-
确认端侧编译过程是否结束
可通过下面命令,观察
ark_aot_compiler
是否退出,退出即表示端侧编译结束。hdc shell "ps -ef | grep aot"
-
确认端侧编译文件是否生成
可通过确认端侧
/data/local/ark-cache/{bundleName}
路径下是否有an/ai文件,确认端侧编译是否完成
-
案例实践
场景介绍
本文案例基于业界编程语言Benchmarks Game中提出的模拟N体问题,编写了类木星体轨道计算程序的ArkTS实现。
实现方式
轨道计算作为一个计算密集型程序,会大量占用系统资源计算能力的任务,需要长时间运行,这段时间会阻塞线程其它事件的处理,不适宜放在主线程进行。
所以,本文案例基于多线程并发机制,以提高CPU利用率,提升应用程序响应速度。关于多线程的实践,可以参考文档OpenHarmony应用多线程能力实践。
针对500万次时间推移的轨道计算,任务不需要长时间(>3分钟)占据后台线程,且是一个个独立的任务时,所以使用TaskPool开启多线程实现:
/**
* 使用TaskPool开启子线程,执行轨道计算任务
* @param totalTimeSteps 时间推移量
*/
export function computeNBodyByTaskPool(totalTimeSteps: number): void {
Logger.info(TAG, "computeNBodyByTaskPool: start executing")
let task: taskpool.Task = new taskpool.Task(computeTask, totalTimeSteps);
try {
Logger.info(TAG, 'computeNBodyByTaskPool: start calculating...')
// 向taskpool线程池派发子线程任务
taskpool.execute(task, taskpool.Priority.HIGH).then((res: number) => {
Logger.info(TAG, 'computeNBodyByTaskPool: executed successfully, total time costed = ' + res + ' ms.')
AppStorage.set<String>('timeCost', 'Total time costed = ' + res + ' ms.')
})
} catch (err) {
Logger.error(TAG, "computeNBodyByTaskPool: execute failed, " + (err as BusinessError).toString())
}
Logger.info(TAG, "computeNBodyByTaskPool: finish executing")
}
而针对5000万次时间推移的轨道计算,任务相对需要较长长时间,所以使用Worker开启多线程实现:
/**
* 使用Worker开启子线程,执行轨道计算任务
* @param totalTimeSteps 时间推移量
*/
export function computeNBodyByWorker(totalTimeSteps: number): void {
Logger.info(TAG, "computeNBodyByWorker: start executing")
let workerInstance = new worker.ThreadWorker("entry/ets/workers/CalculateWorker.ts");
// 设置如何处理,来自worker线程的消息
workerInstance.onmessage = function (e: MessageEvents) {
let data = e.data;
Logger.info(TAG, 'computeNBodyByWorker: executed successfully, total time costed = ' + data.result + ' ms.')
AppStorage.set<String>('timeCost', 'Total time costed = ' + data.result + ' ms.');
}
// 设置由主线程向worker线程发送什么消息
workerInstance.postMessage({'timeSteps': totalTimeSteps});
}
被子线程执行的计算任务如下:
/**
* 运行天体轨道计算程序
* @param totalTimeSteps 时间推移量
* @returns 计算时间
*/
@Concurrent
export function computeTask(totalTimeSteps: number): number {
let start: number = new Date().getTime();
// 建立孤立系统的动量守恒
offsetMomentum();
Logger.info(TAG_IN_TASK, energy().toFixed(9));
// 更新天体在按指定的时间变化后的位置信息
for (let i: number = 0; i < totalTimeSteps; i++) {
advance(0.01);
}
// 判断系统计算前后机械能守恒
Logger.info(TAG_IN_TASK, energy().toFixed(9));
let end: number = new Date().getTime();
return end - start;
}
使用限制
-
本文重点介绍Target AOT模式,仅支持 API 10 及以上版本 Stage 模型的 ArkTS 工程。
-
目前仅 HAP 和 HSP 支持该功能。
-
Node.js 需要 14.19.1 以上版本。
-
仅支持在 64 位 ROM 上运行。
-
不支持混淆,需要关闭混淆功能。
参考资料
