大家好,我是simple。我的理想是利用科技手段来解决生活中遇到的各种问题。
今天跟大家一起探讨一下鸿蒙开发的多线程。ArkTS提供了TaskPool和Worker两种并发能力供开发者选择。
先说个人理解:在轻量、频繁性地需要使用多线程场景使用taskpool,在计算量大、耗时资源大需要使用多线程时使用worker。
概念
-
TaskPool
是一个线程池管理工具,它维护了一组预先创建的线程,通过将任务分配到线程池中执行,降低了整体资源的消耗,提高了系统的整体性能。开发时无需关心线程实例的生命周期,TaskPool
会自动管理线程的创建、复用和销毁。 -
Worker
提供了一种在后台线程中执行脚本的方式,它允许开发者创建独立的工作线程,这些线程可以与主线程并行运行,并且能够与主线程进行通信。其原理是创建一个独立于主线程的执行环境,在这个环境中运行指定的脚本,从而避免阻塞主线程。
2. 适用场景
-
Worker :适用于需要长时间运行且相对独立的任务,例如大量数据的处理、复杂的算法计算等。由于
Worker
创建的是独立线程,它可以在不影响主线程的情况下,持续进行复杂的计算任务。 -
TaskPool :更适合执行多个短时间的任务,尤其是那些可以并行执行的任务。比如在应用启动时,需要同时初始化多个模块的任务,使用
TaskPool
可以将这些任务分配到不同的线程中并行执行,从而提高应用的启动速度。
3. 使用方式
- Worker :创建
Worker
需要指定一个脚本文件,在该脚本文件中编写要执行的任务逻辑。主线程和Worker
线程之间通过postMessage
方法进行通信。以下是一个简单示例:
在模块级entry/build-profile.json5配置文件添加如下配置:
json
"buildOption": {
"sourceOption": {
"workers": [
"./src/main/ets/workers/Worker.ets"
]
}
}
typescript
// 宿主线程中创建Worker对象
const workerInstance = new worker.ThreadWorker("entry/ets/workers/Worker.ets");
// 宿主线程向worker线程传递信息
workerInstance.postMessage({ data: 'test' });
// 宿主线程接收worker线程信息
workerInstance.onmessage = (e: MessageEvents): void => {
// data:worker线程发送的信息
console.info("main thread data is " + e.data);
// 销毁Worker对象
workerInstance.terminate();
}
// 在调用terminate后,执行onexit
workerInstance.onexit = (code) => {
console.log("main thread terminate");
}
workerInstance.onerror = (err: ErrorEvent) => {
console.log("main error message " + err.message);
}
typescript
// Worker.ets
import { worker, MessageEvents, ErrorEvent } from '@kit.ArkTS';
// 创建worker线程中与宿主线程通信的对象
const workerPort = worker.workerPort
// worker线程接收宿主线程信息
workerPort.onmessage = (e: MessageEvents): void => {
// data:宿主线程发送的信息
console.info("main thread data is " + e.data);
// worker线程向宿主线程发送信息
workerPort.postMessage('result');
}
// worker线程发生error的回调
workerPort.onerror = (err: ErrorEvent) => {
console.log("worker.ets onerror" + err.message);
}
- TaskPool :使用
TaskPool
时,开发者只需定义任务函数,然后将任务提交到TaskPool
中即可。TaskPool
会自动选择合适的线程来执行任务。以下是一个使用TaskPool
的示例:
typescript
import { taskpool } from '@kit.ArkTS';
@Concurrent
function add(num1: number, num2: number): number {
return num1 + num2;
}
async function ConcurrentFunc(): Promise<void> {
let task: taskpool.Task = new taskpool.Task(add, 1, 2);
}
4. 资源管理
-
Worker :每个
Worker
都会创建一个独立的线程,因此会占用相对较多的系统资源。当Worker
任务完成后,如果不手动终止,它会一直占用系统资源。 -
TaskPool :
TaskPool
通过线程池的方式管理线程,避免了频繁创建和销毁线程所带来的资源开销。线程池中的线程可以被多个任务复用,从而提高了资源的利用率。
总结
Worker
通过创建独立线程运行指定脚本,适合长时间且独立的任务,需手动管理线程资源并通过消息通信,而 TaskPool
作为线程池管理工具,自动管理线程的创建、复用和销毁,支持多种任务类型,适合多个短时间并行任务。