一、概要
Promise和async/await提供异步并发能力,适用于单次I/O任务的开发场景。详细请参见异步并发概述。
TaskPool和Worker提供多线程并发能力,适用于CPU密集型任务、I/O密集型任务和同步任务等并发场景。详细请参见多线程并发概述。
总结就是:单线程、多线程
二、并发
1.异步并发
是什么?
异步代码会被挂起并在之后继续执行,同一时间只有一段代码执行,适用于单次I/O任务的场景开发,例如一次网络请求、一次文件读写等操作。
异步语法是一种编程语言的特性,允许程序在执行某些操作时不必等待其完成,而是可以继续执行其他操作。
Promise有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)。Promise对象创建后处于pending状态,并在异步操作完成后转换为fulfilled或rejected状态。
没有达到“协程”这样的粒度。
怎么做?
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber);
} else {
reject(new Error('Random number is too small'));
}
}, 1000);
});
promise.then(result => {
console.info(`Random number is ${result}`);
}).catch(error => {
console.error(error.message);
});
then方法的回调函数接收Promise对象的成功结果作为参数,并将其输出到控制台上。如果Promise对象进入rejected状态,则catch方法的回调函数接收错误对象作为参数,并将其输出到控制台上。
其实就是Rx的那套用法。
async function myAsyncFunction() {
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve('Hello, world!');
}, 3000);
});
console.info(String(result)); // 输出: Hello, world!
}
myAsyncFunction();
await是函数语法糖,简化了写法(可以对比上述两种写法就可以发现)。异步的方法需要加上修饰符async
,这点和kotlin中的supend
类似的。
async function myAsyncFunction() {
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve('Hello, world!');
}, 3000);
});
console.info(String(result)); // 输出: Hello, world!
}
myAsyncFunction();
好吧,这里也可以通过try-catch来捕获“被拒绝”的结果。
2.多线程并发
是什么?
并发模型是用来实现不同应用场景中并发任务的编程模型,常见的并发模型分为基于内存共享的并发模型和基于消息通信的并发模型。
这里提及了传输对象有4种。
目前支持传输的数据对象可以分为普通对象、可转移对象、可共享对象、Native绑定对象四种。
1.普通对象:克隆对象,意味着是新对象,基本数据都支持,还有些其他
2.可转移对象:顾名思义,可以把对象转移给其他对象,那么原本的“主人”就不再持有了。
// 定义可转移对象
let buffer = new ArrayBuffer(100);
3.可共享对象:意味着对象可共享,那么老领导和新领导都要对你指手画脚。哎头疼!(指向同一块内存)
// 定义可共享对象,可以使用Atomics进行操作
let sharedBuffer = new SharedArrayBuffer(1024);
4.Native绑定对象
Native绑定对象(Native Binding Object)是系统所提供的对象,该对象与底层系统功能进行绑定,提供直接访问底层系统功能的能力。
当前支持序列化传输的Native绑定对象主要包含:Context和RemoteObject。
Context对象包含应用程序组件的上下文信息,它提供了一种访问系统服务和资源的方式,使得应用程序组件可以与系统进行交互。获取Context信息的方法可以参考获取上下文信息。
RemoteObject对象的主要作用是实现远程通信的功能,它允许在不同的进程间传递对象的引用,使得不同进程之间可以共享对象的状态和方法,服务提供者必须继承此类,RemoteObject对象的创建可以参考RemoteObject的实现。
类似于Binder。
怎么做?
-
TaskPool和Worker的对比
前者是ThreadPoolExcutor,后者也是线程池。
只不过前者偏向于单任务,后者偏向于多任务。 -
@Concurrent装饰器:校验并发函数
在使用TaskPool时,执行的并发函数需要使用该装饰器修饰,否则无法通过相关校验。
import taskpool from '@ohos.taskpool';
@Concurrent
function add(num1: number, num2: number): number {
return num1 + num2;
}
async function ConcurrentFunc(): Promise<void> {
try {
let task: taskpool.Task = new taskpool.Task(add, 1, 2);
console.info("taskpool res is: " + await taskpool.execute(task));
} catch (e) {
console.error("taskpool execute error is: " + e);
}
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
ConcurrentFunc();
})
}
.width('100%')
}
.height('100%')
}
}
可以理解为加上该注解,相当于其放在了runnable中,可以运行在线程中执行。
发送、返回数据这方面,worker倒是有点类似于Handler的消息处理机制了。
三、总结
并发并没有什么新鲜的介绍。