【HarmonyOS NEXT】多线程并发-Worker

一、背景

在鸿蒙开发中提供了两种多线程并发方案,分别是TaskPool与Worker,此篇文章主要总结下Worker

二、Worker概念

1、Worker为应用程序提供一个多线程的运行环境,实现后台线程与宿主线程分离

2、Worker有自己的生命周期,一旦创建不会主动销毁,需手动销毁空闲的Worker

3、作用:在后台线程中处理耗时操作(如:计算密集型或高延迟任务),避免影响主线程(如:UI主线程)

4、目标:将「重量级、长期、有状态」的耗时逻辑从主线程剥离,解决主线程被阻塞导致 UI 无响应的问题

5、运作机制

Worker子线程和宿主线程通过消息传递机制通信,利用序列化、引用传递或转移所有权的机制完成命令和数据的交互

三、注意事项

1、创建Worker

A、自动创建:使用DevEco Studio 单击鼠标右键 > New > Worker,一键生成Worker的模板文件及配置信息

B、手动创建:在工程目录下创建Worker文件,并在build-profile.json5配置Worker文件路径

TypeScript 复制代码
//Stage模型:
"buildOption": {
  "sourceOption": {
    "workers": [
      "./src/main/ets/workers/worker.ets"
    ]
  }
}

2、文件路径

A、Stage模型--->路径规则:{moduleName}/ets/{relativePath}

TypeScript 复制代码
1. // worker线程文件所在路径:"entry/src/main/ets/workers/worker.ets"
2. const workerStage1: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ets');

B、HAR包中加载Worker线程文件--->路径规则:@{moduleName}/ets/{relativePath}

TypeScript 复制代码
1. // @标识路径加载形式:
2. // worker线程文件所在路径: "har/src/main/ets/workers/worker.ets"
3. const workerStage4: worker.ThreadWorker = new worker.ThreadWorker('@har/ets/workers/worker.ets');

3、资源加载

A、同时运行的Worker子线程数量最多为64个(与napi_create_ark_runtime创建的runtime总数不超过80)

B、单次序列化传输的数据量大小限制为16MB

4、模块使用限制

A、只能使用线程安全的库,UI相关的非线程安全库不能使用

B、不支持在多个HAP之间共享使用相同的Worker线程文件

C、不支持在Worker工作线程中AppStorage

D、禁止使用export语法导出

5、异常处理

A、API 18+使用onAllErrors回调捕获异常,Worker线程继续存活

B、API 18以前使用onerror回调捕获异常,Worker线程进入销毁流程,无法继续使用

四、Worker生命周期

生命周期顺序:创建--->运行--->销毁

1、创建阶段

在主线程或父Worker线程中,调用new worker.ThreadWorker(scriptURL)

2、运行阶段

通过 postMessage 和 onmessage 与创建它的线程进行双向通信。

  • 核心方法:

    • parentPort.postMessage(): 发送消息。

    • parentPort.onmessage(): 接收消息。

    • onerror(): 处理错误。

3、销毁阶段

由创建该Worker的线程(父线程)主动调用 worker.terminate()

  • terminate():立即终止

  • close():正常关闭

**关键点:**必须手动触发。对于多级Worker,必须严格遵循 "从子到父"的销毁顺序(即先销毁所有子Worker,再销毁父Worker)

五、怎么用

步骤1:配置构建文件

这一步是保证系统能找到新建的Worker脚本

打开 entry/build-profile.json5 文件,在 buildOption 字段内添加 sourceOption 配置:

步骤2:创建Worker后台脚本

在 entry/src/main/ets/ 目录下,创建 workers 文件夹并创建脚本文件

TypeScript 复制代码
import { MessageEvents, worker,ErrorEvent } from '@kit.ArkTS';

// 1. 获取通信端口
const parentPort = worker.workerPort;

// 2. 监听主线程发来的消息 - 使用正确的MessageEvent类型
parentPort.onmessage = (e: MessageEvents) => {
  console.log('[Worker] 收到数据: ' + e.data);

  // 3. 执行耗时计算 (例如计算斐波那契数列)
  const n: number = e.data;
  const result = fibonacci(n);

  // 4. 将结果发送回主线程
  console.log('[Worker] 计算完成,结果: ' + result);
  parentPort.postMessage(result);
};

// 一个模拟的耗时计算函数
function fibonacci(n: number): number {
  if (n <= 1) return n;
  // 注意:递归版本对较大n值会很慢,这里为演示用
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// 5. 使用正确的ErrorEvent类型处理错误
parentPort.onerror = (ev: ErrorEvent): void => {
  console.error('[Worker] 发生错误: ' + ev.message);
};

步骤3:创建主页面调用Worker

TypeScript 复制代码
import { ErrorEvent, MessageEvents, worker } from '@kit.ArkTS';

@Entry
@Component
struct Index {
  @State result: string = '等待计算';
  @State isCalculating: boolean = false;
  private calcWorker?: worker.ThreadWorker

  build() {
    Column({ space: 20 }) {
      Text('Worker演示')
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 30 })

      Text(this.result)
        .fontSize(24)
        .fontColor(this.isCalculating ? Color.Red : Color.Black)
        .margin({ bottom: 20 })

      Button(this.isCalculating ? '计算中...' : '开始计算')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor(this.isCalculating ? Color.Gray : Color.Blue)
        .enabled(!this.isCalculating)
        .onClick(() => {
          this.startCalculation();
        })

      Button('终止Worker')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor(Color.Orange)
        .onClick(() => {
          this.terminateWorker();
        })

      // 显示进度或状态
      if (this.isCalculating) {
        LoadingProgress()
          .width(50)
          .height(50)
          .margin({ top: 20 })
      }
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .padding(20)
  }

  // 启动Worker计算
  startCalculation() {
    // 1. 先清理可能存在的旧Worker
    this.terminateWorker();

    // 2. 更新UI状态
    this.isCalculating = true;
    this.result = '正在创建Worker...';
    console.log('[UI] 开始计算流程');

    try {
      // 3. 创建Worker实例
      this.calcWorker = new worker.ThreadWorker('entry/ets/worker/DataSyncWorker.ets');
      console.log('[UI] Worker创建成功');

      // 4. 设置Worker回调
      this.calcWorker.onmessage = (e: MessageEvents): void => {
        console.log('[UI] 收到Worker结果: ' + e.data);
        this.result = '计算结果: ' + e.data;
        this.isCalculating = false;

        // 计算完成后可以立即销毁Worker,或者保留以备后用
        this.terminateWorker();
      };

      this.calcWorker.onerror = (ev: ErrorEvent): void => {
        console.error('[UI] Worker发生错误: ' + ev.message);
        this.result = '错误: ' + ev.message;
        this.isCalculating = false;
      };


      // 5. 更新状态并发送计算任务
      this.result = '计算中...';
      console.log('[UI] 向Worker发送计算任务');

      // 计算斐波那契数列第30项(比35项快,适合演示)
      const calculateTarget = 30;
      this.calcWorker.postMessage(calculateTarget);

    } catch (error) {
      console.log('lucy== error',JSON.stringify(error))
      console.error('[UI] 创建Worker失败: ' + error.message);
      this.result = '创建Worker失败';
      this.isCalculating = false;
    }
  }

  // 终止Worker
  terminateWorker() {
    if (this.calcWorker) {
      try {
        this.calcWorker.terminate(); // 直接终止Worker,释放资源
        console.log('lucy== 终止成功')
        console.log('[UI] Worker已成功终止');
      } catch (err) {
        console.log('lucy== 终止失败',JSON.stringify(err))
        console.error('[UI] 终止Worker失败: ' + JSON.stringify(err));
      }
      this.calcWorker = undefined; // 清空实例引用,避免内存泄漏和误操作
    }
  }

  // 页面生命周期:离开时清理Worker
  aboutToDisappear(): void {
    console.log('[UI] 页面即将销毁,清理Worker');
    this.terminateWorker();
  }
}

六、适用场景

A、长耗时任务:执行时间 > 10秒(如大插件解压)

B、长期运行的后台服务(如音乐播放器、实时定位追踪)

C、频繁双向通信(如实时聊天的消息处理)

D、需指定专属线程(避免切换、绑定特性)

相关推荐
行者9618 小时前
Flutter与OpenHarmony深度整合:打造高性能自定义图表组件
flutter·harmonyos·鸿蒙
以太浮标18 小时前
华为eNSP模拟器综合实验之- HRP(华为冗余协议)双机热备
运维·网络·华为·信息与通信
Van_captain18 小时前
rn_for_openharmony常用组件_Empty空状态
javascript·开源·harmonyos
cn_mengbei18 小时前
鸿蒙PC开发指南:从零配置Qt环境到实战部署完整流程
qt·华为·harmonyos
前端世界18 小时前
从能跑到好跑:基于 DevEco Studio 的鸿蒙应用兼容性实践总结
华为·harmonyos
行者9618 小时前
Flutter适配OpenHarmony:高效数据筛选组件的设计与实现
开发语言·前端·flutter·harmonyos·鸿蒙
Van_Moonlight18 小时前
RN for OpenHarmony 实战 TodoList 项目:底部 Tab 栏
javascript·开源·harmonyos
Van_Moonlight18 小时前
RN for OpenHarmony 实战 TodoList 项目:浮动添加按钮 FAB
javascript·开源·harmonyos
hqzing19 小时前
低成本玩转鸿蒙容器的丐版方案
docker·harmonyos