HarmonyOS应用开发-关于鸿蒙中的异步Promise和线程taskPool,worker
HarmonyOS应用开发-关于鸿蒙中的异步(Promise)和线程(taskPool,worker)
前言
学习鸿蒙过程中,对于鸿蒙的线程和异步可能会存在很多疑惑,什么是异步,什么时候用异步。或者什么时候用线程?
本文重点讲下三种方法的区别和使用场景,不注重具体如何使用代码,这里一笔带过。
鸿蒙对于异步提供了三种处理方式(注意这里是异步,不是特指线程):
1.JS原生的Promise异步
2.taskPool线程
3.worker常驻线程
Promise异步
对于我们做 Android开发,经常提到异步,就习惯性的认为是起个子线程来执行。但是当我们做鸿蒙开发时候,要注意Promise异步和线程两个概念不同。
1.Promise异步仍然是在当前线程中运行任务,结果以异步方式返回(接口回调方式)
2.当我们对某个方法定义为Promise异步执行,那么当前线程就会在空闲时候执行当前方法,结果以异步方式返回
使用方法
●方法1
testFunc(suc: boolean): Promise<string> {
return new Promise((resolve, reject) => {
if (suc) {
resolve("success")
} else {
reject("fail")
}
})
}
●方法2
async testFunc(suc: boolean): Promise<string> {
if (suc) {
return "success"
}
throw new Error("fail")
}
两种方法各有好处,看各自喜欢和习惯以及实际场景。
调用
●场景1 - 异步执行方法获取结果
testFunc1(true).then((result: string) => {
// resolve返回的结果在这里输出
}).catch((e: Error) => {
// reject 抛出的异常在这里触发
})
●场景2 - 同步等待方法执行完成
async call() {
try {
const suc = await this.testFunc(true)
} catch (e) {
// reject error
}
}
场景2使用了await修饰,改修饰符要求方法必须使用async修饰,且异常通过try…catch来捕获。
Promise使用场景
1.模块或者接口通过异步封装
2.单次IO操作(网络或小文件读写)
3.耗时操作(非长时间耗时,必须保证CPU可以被释放)
taskPool
对于一些耗时操作,使用Promise占用了主线程资源,可能会导致ANR,所以出现了taskPool来保证可以起子线程处理耗时操作。
taskPool存活最长时间为3分钟,运行超过3分钟,那么会被系统杀掉。
如果在taskPool里进行了网络请求或者文件读写,那么网络请求和文件读写的耗时是不计算在3分钟里的。
由于鸿蒙线程使用了Actor模型,导致taskPool新起的子线程和主线程的内存是不共享的。所以无法在子线程直接操作主线程的内存。
一定程度上解决了多线程问题,但是对于多线程操作也带来一定的影响。
注意这里是一定程度上解决多线程问题,实质上多线程问题还是会存在。比如主线程和子线程同时对一个文件进行读写操作,会存在多线程问题。
由于内存隔离机制,所以子线程在启动时候,可以接收来自主线程的数据只能是二进制流或者基本数据类型。同理 子线程运行完毕后,可以回传数据给主线程,也只能是二进制流或者基本数据类型。推荐使用JSON字符串。
使用方法
class TestA {
execute() {
taskpool.execute(calc, "123sss").then((result) => {
const target = result as number
})
}
}
@Concurrent
function calc(value: string): number {
return 123
}
注意对于taskPool调用的函数,必须声明为全局函数,且使用 装饰器 @Concurrent 来修饰。
如果条件不满足,那么运行时候,系统会打印错误日志进行提示。
E [ecmascript] Function is not concurrent
E [(worker.cpp:414)(InitTaskPoolFunc)] taskpool:: InitTaskPoolFunc fail
Worker
我们经常会遇到,存在一个特别耗时的操作,或者可能存在业务需要一直死循环运行。那么这个时候就涉及到常驻线程了。
通过worker可以启动一个线程,该线程不存在时长限制,可以一直存在,所以我们可以在里边做一些耗时操作。
但是有几个特点:
1.worker线程最多可以在APP里同时存在8个一起运行,超出数量的不会运行。但是创建可以创建多个,所以当worker不需要的时候要及时停止运行
2.worker对内存有影响,每个空worker起来后就会占用2MB左右内存
3.worker里可以继续启动taskPool执行逻辑
如何使用
worker 比较特殊,需要在当前module的build-profile.json5配置文件中配置一下worker定义的文件的路径。
该wSocketWorker文件中,会通过系统 workerPort.onmessage 来接收来自主线程或其他线程的信息,接收到信息后进行处理。
workerPort通过如下方式声明。
let workerPort: ThreadWorkerGlobalScope = worker.workerPort;
该SocketWorker是我们自定义的一个文件,可以看做是我们当前定义的Worker和其他线程交互的一个接口,也是当前Worker线程的入口。
注意这里使用workerPort要在全局环境中使用,不能放到类中。
如何在主线程和Worker交互
test() {
let send = new worker.ThreadWorker("./SocketWorker.ets");
send.onexit = (code) => {
// 运行结束时候,接收来自worker的信息
}
send.postMessage(new SocketParam(1, 2, "s", 2, 3))
}
我们在主线程需要启动worker和worker交互的地方,通过上述代码即可启动我们定义好的worker。同时在onexit监听worker结束时候的回调。
对比Promise,taskPool和worker
1.对于单次IO,非阻塞性任务,可以使用Promise
2.对于UI刷新频繁的场景,不推荐使用Promise执行一些耗时逻辑,可能会造成UI刷新卡顿或者Promise逻辑无法得到执行
3.对于IO密集型任务,非常驻任务,建议使用taskPool执行。控制好时间,不要超过3分钟
4.对于常驻任务,使用worker
5.对于耗时,阻塞任务使用worker
6.使用Promise时候不需要考虑多线程问题,使用worker和taskPool时候,如果对文件进行写操作,注意多线程问题。
写在最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
获取这份完整版高清学习路线,请点击→
鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→
《鸿蒙 (OpenHarmony)开发入门教学视频》
《鸿蒙生态应用开发V2.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
《鸿蒙开发进阶》
●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
《鸿蒙进阶实战》
●ArkTS实践
●UIAbility应用
●网络案例
……