目录

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

1.1 TaskPool 基础用法:加法计算

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

1.3 TaskPool 跨线程通信:sendData/onReceiveData

2.Worker:重量级独立线程

2.1 Worker 基础通信:Hello World

2.2 Worker 计算任务:倍数计算

2.3 Worker 与 UI 状态同步:AppStorage

3.总结与比较


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

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

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

1.1 TaskPool 基础用法:加法计算

代码示例:

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 调用

    代码示例:

    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

    代码示例:

    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

    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

    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

    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 线程调用

    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 线程

    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 文件路径

    Logo

    讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

    更多推荐