1.什么是并发?
并发
指在同一时间内,存在多个任务同时执行的情况。
多核设备
:这些任务可能同时在不同CPU上并行执行
。单核设备
:多个并发任务
不会在同一时刻并行执行,但是CPU会在某个任务休眠或进行I/O操作等状态下切换任务
,调度执行其他任务
,提升CPU的资源利用率。
并发核心概念
- 并发与并行
- 并发:逻辑上的"同时执行"(单核通过任务切换实现,多核可真正并行)。
- 并行:物理上的同时执行(依赖多核设备)。
- 目标:提升响应速度与帧率,避免主线程阻塞。
2.为了提升应用的响应速度与帧率,避免耗时任务对UI主线程的影响,ArkTS提供了集中策略?
异步并发
异步代码在执行到一定程度后会被暂停,以便在未来某个时间点继续执行,这种情况下,同一时间只有一段代码在执行。ArkTS通过Promise和async/await提供异步并发能力,适用于单次I/O任务的开发场景。
多线程并发
允许在同一时间段内同时执行多段代码。在UI主线程继续响应用户操作和更新UI的同时,后台线程也能执行耗时操作,从而避免应用出现卡顿。ArkTS通过TaskPool和Worker提供多线程并发能力,适用于耗时任务等并发场景。
3.ArkTS并发策略对比
策略 | 异步并发 | 多线程并发 |
---|---|---|
实现方式 | Promise + async/await |
TaskPool (线程池) + Worker (独立线程) |
执行特性 | 单线程,代码分段暂停/恢复 | 多线程并行执行 |
适用场景 | 单次I/O任务(如网络请求、文件读写) | CPU密集型任务、耗时操作(如图像处理) |
线程阻塞 | 不阻塞主线程,但代码串行执行 | 后台线程执行,完全避免主线程卡顿 |
资源开销 | 低(无线程创建开销) | 较高(需管理线程生命周期) |
关键要点归总
-
异步并发
- 本质:单线程任务调度,通过事件循环实现非阻塞。
- 优势:轻量级,适合简单I/O任务。
- 限制 :无法利用多核性能,复杂任务可能导致回调嵌套(需
async/await
优化)。
-
多线程并发
- 核心对象 :
- TaskPool:线程池复用,避免频繁创建/销毁线程。
- Worker:独立线程,适合长时任务。
- 数据传输 :
- 基本类型:直接拷贝传输。
- 复杂对象 :需序列化(如
JSON
)或共享内存(谨慎使用)。
- 注意:线程间通信需通过消息传递,避免共享资源竞争。
- 核心对象 :
4.应用场景选择
任务类型 | 推荐策略 | 示例场景 |
---|---|---|
单次I/O操作 | 异步并发 | 请求API、读取本地文件 |
CPU密集型 | 多线程(TaskPool) | 图像处理、数据加密解密 |
长时任务 | 多线程(Worker) | 后台下载、持续日志写入 |
UI交互响应 | 主线程 + 异步 | 按钮点击后非阻塞更新UI |
5.异步并发概述 (Promise和async/await)
异步并发核心概念
-
本质
- 单线程非阻塞任务调度,同一时间仅执行一段代码。
- 通过事件循环(Event Loop)实现任务挂起与恢复,避免主线程阻塞。
-
适用场景
- 单次I/O操作(如网络请求、文件读写)
- 不适用于CPU密集型任务(会阻塞主线程)
Promise与async/await对比
特性 | Promise | async/await |
---|---|---|
本质 | 异步状态管理对象 | Promise的语法糖,简化异步代码编写 |
代码风格 | 链式调用(.then().catch() ) |
同步式写法,逻辑更直观 |
错误处理 | 通过.catch() 捕获异常 |
通过try/catch 捕获异常 |
返回值 | 返回Promise对象 | 返回Promise对象 |
可读性 | 回调嵌套复杂时较差 | 线性执行,可读性高 |
Promise核心要点
-
三种状态
pending
(进行中) →fulfilled
(成功) 或rejected
(失败)- 状态不可逆 :一旦变为
fulfilled
或rejected
,不可再改变。
-
基本用法
typescriptconst promise = new Promise((resolve, reject) => { // 异步操作(如setTimeout、文件读写) if (成功) resolve(result); else reject(error); });
-
链式调用:
typescriptpromise.then(result => { ... }) .catch(error => { ... });
-
-
关键注意
-
未处理的reject 会触发
unhandledrejection
事件 → 需全局监听:typescripterrorManager.on('error', (err) => { ... });
-
完整例子如下,以下代码创建了一个Promise对象并模拟了一个异步操作:
typescript
const promise: Promise<number> = new Promise((resolve: Function, reject: Function) => {
setTimeout(() => {
const randomNumber: number = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber);
} else {
reject(new Error('Random number is too small')); }}, 1000);})
上述代码中,setTimeout函数模拟了一个异步操作,并在1秒钟后随机生成一个数字。如果随机数大于0.5,则执行resolve回调函数并将随机数作为参数传递;否则执行reject回调函数并传递一个错误对象作为参数。
async/await核心要点
-
语法规则
- 函数声明 :用
async
标记异步函数(如async function fetchData()
) - 等待Promise :用
await
暂停执行,直到Promise完成(await promise
)
- 函数声明 :用
-
代码示例
typescriptasync function myAsyncFunc(): Promise<string> { try { const result = await new Promise(resolve => { setTimeout(() => resolve('Hello'), 3000); }); return result; } catch (error) { console.error(error); throw error; // 抛出异常会被外层catch捕获 } }
-
优势与限制
- ✅ 代码扁平化:避免回调地狱(Callback Hell)
- ❌ 滥用风险 :若在循环中误用
await
,可能导致性能下降
完整例子如下,下面是一个使用async/await的例子,其中模拟了一个以同步方式执行异步操作的场景,该操作会在3秒钟后返回一个字符串。
typescript
async function myAsyncFunction(): Promise<string> {
const result: string = await new Promise((resolve: Function) => {
setTimeout(() => {
resolve('Hello, world!'); }, 3000); });
console.info(result); // 输出: Hello, world! return result;}
@Entry@Componentstruct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(async () => {
let res = await myAsyncFunction();
console.info("res is: " + res);
})}
.width('100%')
}
.height('100%')
}}
错误处理对比
方式 | Promise | async/await |
---|---|---|
成功处理 | .then(result => { ... }) |
const result = await promise |
失败处理 | .catch(error => { ... }) |
try { ... } catch (error) { ... } |
全局异常捕获 | 监听unhandledrejection 事件 |
结合try/catch 与全局监听 |
6.多线程并发(TaskPool和Worker)
任务池(TaskPool)
作用是为应用程序提供一个多线程的运行环境,降低整体资源的消耗、提高系统的整体性能,且您无需关心线程实例的生命周期。具体接口信息及使用方法详情请见TaskPool。
TaskPool运作机制

Worker
主要作用是为应用程序提供一个多线程的运行环境,可满足应用程序在执行过程中与宿主线程分离,在后台线程中运行一个脚本进行耗时操作,极大避免类似于计算密集型或高延迟的任务阻塞宿主线程的运行。具体接口信息及使用方法详情请见Worker。
Worker运作机制

TaskPool vs Worker 核心对比
特性 | TaskPool | Worker |
---|---|---|
本质 | 线程池动态调度(任务队列 + 线程复用) | 独立线程(需手动管理生命周期) |
适用场景 | 短时、高频的CPU密集型任务(如计算) | 长时、独立的后台任务(如下载、日志) |
线程数量 | 动态扩容(上限=设备物理核数) | 最多64个,需手动销毁 |
开发复杂度 | 低(系统自动管理线程) | 较高(需处理线程创建、销毁、通信) |
数据传输限制 | 16MB(支持序列化对象) | 16MB(支持序列化对象) |
生命周期 | 任务结束自动释放线程资源 | 需手动调用close() 或terminate() 销毁 |
错误处理 | 通过Promise的.catch() 捕获 |
通过onerror 回调捕获 |
TaskPool核心要点
1. 使用场景
- CPU密集型短任务:如图像处理、加密解密。
- 高频小任务:避免频繁创建线程的开销。
2. 关键规则
- 装饰器 :任务函数必须用
@Concurrent
修饰。 - 执行时间:单任务函数耗时≤3分钟(不含异步I/O)。
- 数据传输:仅支持可序列化类型(如基本类型、ArrayBuffer)。
3. 示例代码
typescript
// 定义任务函数(必须@Concurrent)
@Concurrent
function add(a: number, b: number): number {
return a + b;
}
// 提交任务到线程池
async function runTask() {
const task = new taskpool.Task(add, 1, 2);
const result = await taskpool.execute(task);
console.log(`Task结果: ${result}`); // 输出3
}
4. 注意事项
- 禁止闭包:任务函数内不能访问外部变量。
- 线程安全库:只能使用线程安全的API(如不可操作UI)。
Worker核心要点
1. 使用场景
- 长时任务:如后台下载、持续数据同步。
- 独立线程需求:需明确控制线程生命周期。
2. 关键规则
- 线程数量:最多同时运行64个Worker。
- 生命周期 :必须手动调用
close()
销毁。 - 文件路径 :Worker文件需放在指定目录(如
entry/ets/workers/
)。
3. 示例代码
typescript
// 主线程:创建Worker并通信
const worker = new worker.ThreadWorker('entry/ets/workers/myWorker.ets');
worker.postMessage('开始任务'); // 发送消息
worker.onmessage = (e) => {
console.log(`收到Worker回复: ${e.data}`);
};
// Worker线程(myWorker.ets)
workerPort.onmessage = (e) => {
workerPort.postMessage('任务完成'); // 回复消息
};
4. 注意事项
- 多级Worker:父Worker销毁前需先销毁子Worker。
- 内存限制:所有Worker内存总和≤1.5GB或物理内存60%。
场景选择口诀
-
TaskPool扛短快,Worker长时独立在;
-
高频计算用池化,下载日志Worker带。
错误处理对比
策略 | 错误捕获方式 | 示例 |
---|---|---|
TaskPool | 通过Promise的.catch() |
taskpool.execute(task).catch(e => {}) |
Worker | 通过onerror 回调 |
worker.onerror = (err) => { ... } |
记忆要点
-
TaskPool
- 线程池复用,适合短任务。
@Concurrent
装饰器 + 可序列化参数。
-
Worker
- 独立线程,手动管理生命周期。
- 主从线程通过
postMessage
通信。