鸿蒙ArkTS多线程:TaskPool & Worker

目录

1.TaskPool:轻量级并发任务处理

[1.1 TaskPool 基础用法:加法计算](#1.1 TaskPool 基础用法:加法计算)

[1.2 TaskPool 网络请求:并发 HTTP 调用](#1.2 TaskPool 网络请求:并发 HTTP 调用)

[1.3 TaskPool 跨线程通信:sendData/onReceiveData](#1.3 TaskPool 跨线程通信:sendData/onReceiveData)

2.Worker:重量级独立线程

[2.1 Worker 基础通信:Hello World](#2.1 Worker 基础通信:Hello World)

[2.2 Worker 计算任务:倍数计算](#2.2 Worker 计算任务:倍数计算)

[2.3 Worker 与 UI 状态同步:AppStorage](#2.3 Worker 与 UI 状态同步:AppStorage)

3.总结与比较


在鸿蒙应用开发中,UI 线程负责渲染界面和响应用户交互,若在 UI 线程中执行耗时操作 (如网络请求、复杂计算),会导致界面卡顿甚至 ANR(应用无响应)。因此,鸿蒙提供了TaskPoolWorker两种多线程方案,用于将耗时任务转移到后台线程执行,保证 UI 流畅。本篇博客将结合实战代码,深度解析这两种多线程机制的核心原理、使用场景与相关实践。

1.TaskPool:轻量级并发任务处理

TaskPool 是鸿蒙推荐的轻量级多线程方案,通过**@Concurrent装饰器**标记并发函数,由系统自动调度线程池执行任务,无需手动管理线程生命周期。

1.1 TaskPool 基础用法:加法计算

代码示例:

TypeScript 复制代码
import { taskpool } from "@kit.ArkTS"

@Concurrent     // 标记为并发函数,可被TaskPool调度
function add(num1: number, num2: number): number {
  return num1 + num2
}

async function execTask(num1:number,num2: number): Promise<number> {

  // 创建Task对象,绑定并发函数与参数
  let task: taskpool.Task = new taskpool.Task(add, num1, num2)

  // 执行任务,默认返回Promise<Object>,需用as做类型断言
  let result = await taskpool.execute(task) as number

  console.log("结果为:" + result)

  return result
}


@Entry
@Component
struct Demo1 {
  @State value1: string = ""
  @State num1: number = 0
  @State num2: number = 0
  build() {

    Column({ space: 20 }) {

      Text("计算的结果为:" + this.value1)

      TextInput({placeholder:"1.请输入一个数:"}).onChange((value)=>{
        this.num1 = Number(value)
      })
      TextInput({placeholder:"2.请输入一个数:"}).onChange((value)=>{
        this.num2 = Number(value)
      })

      // Button("点击开始线程[taskpool]").onClick(() => {
      //
      //   let resultObject = execTask(this.num1,this.num2)
      //
      //   resultObject.then((value) => {
      //
      //     this.value1 = value + ""    // Object -> string
      //
      //   })
      // })

     Button("点击开始线程[taskpool]").onClick(async() => {

       this.value1 = (await execTask(this.num1,this.num2)).toString()

     })

      // Button("点击开始线程[taskpool]").onClick(() => {
      //
      //   execTask(this.num1,this.num2).then((value) => {
      //     this.value1 = value.toString()    // Object -> string
      //   })
      //
      // })

    }.width("100%").height("100%").justifyContent(FlexAlign.Center)
  }
}

代码解析:

  • @Concurrent装饰器 :标记add为并发函数,使其可被 TaskPool 识别并调度。
  • Task 对象创建 :通过new taskpool.Task(add, num1, num2)绑定函数与参数。
  • 类型断言taskpool.execute默认返回Promise<Object>,需用as number将结果转为具体类型。
  • 异步更新 UI :通过await等待任务完成,将结果同步到 UI 线程更新界面。

运行结果:

1.2 TaskPool 网络请求:并发 HTTP 调用

代码示例:

TypeScript 复制代码
import { taskpool } from "@kit.ArkTS"
import { http } from "@kit.NetworkKit"

@Concurrent
async function httpFunc(url: string): Promise<string> {
  let result: string = await new Promise((success: Function, fail: Function) => {
    //构建http对象
    let httpRequest = http.createHttp()
    httpRequest.request(url,
      (error, datas) => {
        if (!error) {
          let resultStr = datas.result
          console.log("得到的数据为:" + resultStr)
          success(resultStr)
        } else {
          fail(new Error("处理结果出现问题"))
        }
        // error ? fail(new Error("请求失败")) : success(datas.result)
      })

  })
  console.log("处理异步消息后after:" + result)
  return result
}

async function execTaskPool(url: string): Promise<string> {
  let resultMsg = await taskpool.execute(httpFunc, url) as string // 用 `as string` 做类型断言,把 Object 强制转为 string
  return resultMsg
}

@Entry
@Component
struct Chapter2 {
  @State message: string = '';

  build() {
    Column() {
      Text(this.message).fontSize(18)

      Button("发起网络请求[TaskPool]").onClick(() => {
        // httpResult是Promise<string>类型
        let httpResult =
          execTaskPool("http://apis.juhe.cn/idioms/query?key=89deff9ec40d86716ba71b57df74768a&wd=专心致志")

        httpResult.then((value) => {

          // this.message = value
          this.message = JSON.parse(value)?.result?.jbsy?.[0]

        })
      })

      // Button("发起网络请求[TaskPool]").onClick(async() => {
      //
      //   let result = await execTaskPool("")
      //   this.message = JSON.parse(value)?.result?.jbsy?.[0]
      //
      // })

    }.width("100%").height("100%").justifyContent(FlexAlign.Center)

  }
}

代码解析:

  • 并发网络请求 :将 HTTP 请求封装为@Concurrent函数,避免阻塞 UI 线程。
  • Promise 封装:用 Promise 包裹 http 请求,统一处理成功 / 失败回调。
  • 结果解析 :通过as string断言结果类型,解析 JSON 后更新 UI。

运行结果:

1.3 TaskPool 跨线程通信:sendData/onReceiveData

代码示例:

TypeScript 复制代码
import { taskpool } from "@kit.ArkTS"

@Concurrent
async function execSendTask() {
  let result1: string = await new Promise((success: Function, fail: Function) => {
    setTimeout(() => {
      success("执行成功的消息")
    }, 3000)

  })

  console.log("1.处理异步消息后after:" + result1)
  taskpool.Task.sendData(result1)   // 向UI线程发送数据
  console.log("2.task end:")
}

async function taskPoolExec(): Promise<string> {

  let task: taskpool.Task = new taskpool.Task(execSendTask)
  taskpool.execute(task)

  // 接收TaskPool线程发送的数据
  let r1 : string = await new Promise((success:Function)=>{
    task.onReceiveData((str: string) => {
      console.log("接受的数据为:" + str)
      success(str)
    })
  })
  return r1
}

@Entry
@Component
struct Chapter4 {
  @State str: string = "1111"

  build() {
    Column() {
      Text(this.str)

      Button("点击请求").onClick(async () => {
        this.str = await taskPoolExec()
      })

    }.width("100%").height("100%").justifyContent(FlexAlign.Center)

  }
}

代码解析:

  • 线程间通信 :通过taskpool.Task.sendData在并发函数中发送数据,task.onReceiveData在 UI 线程接收数据。
  • 异步等待结果:用 Promise 封装接收逻辑,确保 UI 线程能获取到后台线程的执行结果。

运行结果:

2.Worker:重量级独立线程

Worker 适用于需要长期运行的后台任务(如 WebSocket 长连接、持续数据处理),拥有独立的执行上下文,需手动管理线程生命周期。

2.1 Worker 基础通信:Hello World

Step 1:配置 Worker 文件路径(build-profile.json5)

Step 2:Worker 线程代码(worker.ets)

TypeScript 复制代码
import { worker } from "@kit.ArkTS"

//创建worker线程对象
let wk = worker.workerPort
// 接收UI线程消息
wk.onmessage = (e) => {
  let str = e.data as string
  console.log("worker线程接受UI传递的消息为:" + str)

  // 向UI线程返回结果
  setTimeout(() => {
    wk.postMessage("Worker返回:Hello UI!")
  }, 3000)
}

Step 3:UI 线程调用 Worker

TypeScript 复制代码
import { worker } from "@kit.ArkTS"

@Entry
@Component
struct Chapter5 {
  @State msg: string = ""

  build() {

    Column() {
      Text(this.msg).fontSize(20)
      Button("启动Worker线程").onClick(() => {

        // 在UI的视图中创建worker线程,指定线程文件路径
        let worker1 = new worker.ThreadWorker("entry/ets/workers/worker.ets")

        // 发送消息到Worker
        worker1.postMessage("Hello Worker!")

        // 接收Worker返回的消息
        worker1.onmessage = (e) => {
          let str = e.data as string
          console.log("UI视图接受到的线程传递消息为:" + str)
          this.msg = str
        }
      })

    }.width("100%").height("100%").justifyContent(FlexAlign.Center)

  }
}

代码解析:

  • 配置 Worker 路径 :若选择手动创建,必须在build-profile.json5中注册 Worker 文件,否则系统无法识别。
  • 线程双向通信 :通过postMessage发送消息,onmessage接收消息,实现 UI 与 Worker 的双向通信。
  • 独立执行上下文:Worker 拥有独立的内存空间,不能直接访问 UI 线程的变量,需通过消息传递数据。

运行结果:

2.2 Worker 计算任务:倍数计算

Worker 线程代码(workerone.ets)

TypeScript 复制代码
import { worker } from "@kit.ArkTS"

// 创建worker线程对象
let wk1 = worker.workerPort

wk1.onmessage = (datas) => {

  let value = datas.data as string
  console.log("接受的数据为:" + value)

  setTimeout(() => {

    let result1 = Number(value) * 2
    console.log("result1:" + result1)

    //发送字符串类型
    wk1.postMessage("子线程计算的结果为:" + result1)

    //wk1.postMessage(result1)

  }, 3000)


}

UI 线程调用

TypeScript 复制代码
import { worker } from "@kit.ArkTS"

@Entry
@Component
struct Chapter6 {
  @State num1: string = ""
  @State result1: string = "结果为:"

  build() {

    Column({ space: 20 }) {
      Text(this.result1).fontSize(30).fontColor(Color.Black)

      TextInput({ placeholder: "请输入一个数:" }).onChange((value) => {
        this.num1 = value
        console.log("输入的数的值为:" + this.num1)
      })

      Button("计算2倍结果[Worker]").onClick(() => {

        // 创建worker线程对象
        let wk2 = new worker.ThreadWorker("entry/ets/workers/workerone.ets")
        wk2.postMessage(this.num1)

        wk2.onmessage = (e) => {
          let r = e.data as string
          console.log("接受UI:" + r)
          this.result1 = r
        }

      })

    }.width("100%").height("100%").justifyContent(FlexAlign.Center)
  }
}

运行结果:

2.3 Worker 与 UI 状态同步:AppStorage

当需要在 Worker 中更新全局状态时,可通过AppStorage实现跨线程状态同步:

UI 线程

TypeScript 复制代码
import { worker } from "@kit.ArkTS"

// let wrk = AppStorage.link<string>("wrk")

@Entry
@Component
struct Chapter7 {
  @State num1: string = ""
  @State result1: string | undefined = "结果为:"
  @StorageLink("wrk") @Watch("changeResult") wrk: string = ""

  changeResult() {
    console.log("wrk的变化")
    this.result1 = AppStorage.get<string>("wrk")
  }

  build() {

    Column({ space: 20 }) {
      Text(this.result1).fontSize(30).fontColor(Color.Black)

      TextInput({ placeholder: "请输入一个数:" }).onChange((value) => {
        this.num1 = value
        console.log("输入的数的值为:" + this.num1)
      })

      Button("计算并同步状态").onClick(() => {

        let wk2 = new worker.ThreadWorker("entry/ets/workers/workerone.ets")
        wk2.postMessage(this.num1)

        wk2.onmessage = (e) => {
          let r = e.data as string
          console.log("接受UI:" + r)
          AppStorage.set<string>("wrk", r)
        }

      })

    }.width("100%").height("100%").justifyContent(FlexAlign.Center)
  }
}

代码解析:

  • @StorageLink装饰器 :绑定 UI 组件与AppStorage中的状态,状态变化时自动更新 UI。
  • 跨线程状态同步 :Worker 通过postMessage发送结果,UI 线程将结果存入AppStorage,触发全局状态更新。

运行结果:

3.总结与比较

鸿蒙的多线程机制为开发者提供了灵活的后台任务处理能力,TaskPool 适合轻量级并发任务,Worker 适合重量级长期任务。在实际开发中,需根据任务特性选择合适的方案,并结合 Promise、类型断言、状态同步等技术,确保多线程代码的健壮性与可维护性。

特性 TaskPool Worker
定位 轻量级并发任务池 独立的重量级线程
适用场景 CPU 密集型、短周期、高并发任务 IO 密集型、长周期、持续运行任务
线程管理 系统自动调度与复用线程 开发者手动创建与管理线程
通信方式 基于 Promise 回调、sendData/onReceiveData 基于 postMessage/onmessage 双向通信
配置依赖 API 11+ 无需配置 可选择在build-profile.json5中配置 Worker 文件路径
相关推荐
前端不太难3 小时前
为什么 HarmonyOS PC 应用离不开文档模型
华为·状态模式·harmonyos
猛扇赵四那边好嘴.10 小时前
Flutter 框架跨平台鸿蒙开发 - 非遗文化查询:传承中华文化瑰宝
flutter·华为·harmonyos
小学生波波10 小时前
HarmonyOS6 - 鸿蒙AI人脸比对实战案例
ai·arkts·鸿蒙·harmonyos6·比对人脸
知南x12 小时前
【华为昇腾DVPP/AIPP学习篇】(1)工程结构介绍
学习·华为·昇腾·cann·dvpp
m0_6855350812 小时前
Zemax光学设计MTF子午和弧矢分开大,
华为·光学·光学设计·光学工程·镜头设计
小风呼呼吹儿13 小时前
Flutter 框架跨平台鸿蒙开发 - 家庭用药清单:智能管理家庭药品
flutter·华为·harmonyos
纯爱掌门人13 小时前
鸿蒙端云一体化开发(二):云数据库
数据库·华为·harmonyos·端云一体化
小雨青年13 小时前
【鸿蒙原生开发会议随记 Pro】 数据存储架构 RelationalStore 在复杂资产管理中的应用
华为·架构·harmonyos
时光慢煮14 小时前
基于 Flutter × OpenHarmony 的文件管家 —— 构建文件类型分类区域
flutter·华为·开源·openharmony