HarmonyOS 5.0应用开发——多线程Worker和@Sendable的使用方法

发布于:2025-03-01 ⋅ 阅读:(9) ⋅ 点赞:(0)

【高心星出品】

多线程Worker和@Sendable的使用方法

Worker在HarmonyOS中提供了一种多线程的实现方式,它允许开发者在后台线程中执行长耗时任务,从而避免阻塞主线程并提高应用的响应性。

@Sendable 注解主要用于标记那些需要在多线程环境中共享的数据对象或函数。被 @Sendable 标记的对象或函数可以在不同的线程之间高效地传输数据,这主要得益于 ArkTS 的序列化和反序列化机制。

开发步骤

【案例需求】 接下来要实现一个案例,创建两个子线程,一个子线程负责数据求和,一个子线程负责数据相减,UI线程提供共享数据给这两个子线程,子线程运行结果返回给UI线程。

  • 创建两个worker。

    在ets/下创建一个workers目录,在该目录下创建worker。这两个worker负责接受UI线程传过来的数据,并且负责子线程运行实体,并将结果发送给UI线程。

在这里插入图片描述

在这里插入图片描述

  • addworker的代码
import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
import { Temp } from '../pages/Index';

const workerPort: ThreadWorkerGlobalScope = worker.workerPort;

/**
 * Defines the event handler to be called when the worker thread receives a message sent by the host thread.
 * The event handler is executed in the worker thread.
 *
 * @param event message data
 */
// 线程运行实体
function add(temp:Temp){
   let a=temp.a
  let b=temp.b
  temp.a+=5
  return a+b
}
// 子线程接受UI线程信息并处理
workerPort.onmessage = async (event: MessageEvents) => {
  if(event)
  {
    // 模拟线程睡眠2s
    await new Promise((resolve:(v:number)=>void)=>{
      setTimeout(()=>{resolve(10)},2000)
    })
    // 解析获取ui线程发送的数据
    let t=event.data as Temp
    // 子线程向UI线程发送消息
    workerPort.postMessage(add(t))
  }
};

/**
 * Defines the event handler to be called when the worker receives a message that cannot be deserialized.
 * The event handler is executed in the worker thread.
 *
 * @param event message data
 */
workerPort.onmessageerror = (event: MessageEvents) => {
};

/**
 * Defines the event handler to be called when an exception occurs during worker execution.
 * The event handler is executed in the worker thread.
 *
 * @param event error message
 */
workerPort.onerror = (event: ErrorEvent) => {
};
  • jianworker的代码
import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
import { Temp } from '../pages/Index';

const workerPort: ThreadWorkerGlobalScope = worker.workerPort;

/**
 * Defines the event handler to be called when the worker thread receives a message sent by the host thread.
 * The event handler is executed in the worker thread.
 *
 * @param event message data
 */
// 线程运行实体
function jian(t:Temp){
  let a=t.a
  let b=t.b
  t.a-=5
  return Math.abs(a-b)
}
// 子线程接受UI线程的信息 并运行
workerPort.onmessage = async (event: MessageEvents) => {
  if(event){
    // 模拟线程睡眠2s
    await new Promise((resolve:(v:string)=>void)=>{
      setTimeout(()=>{
        resolve('a')
      },2000)
    })
    let t=event.data as Temp
    // 向UI线程发送消息
    workerPort.postMessage(jian(t))
  }
};

/**
 * Defines the event handler to be called when the worker receives a message that cannot be deserialized.
 * The event handler is executed in the worker thread.
 *
 * @param event message data
 */
workerPort.onmessageerror = (event: MessageEvents) => {
};

/**
 * Defines the event handler to be called when an exception occurs during worker execution.
 * The event handler is executed in the worker thread.
 *
 * @param event error message
 */
workerPort.onerror = (event: ErrorEvent) => {
};
  • Index.ets代码
import { MessageEvents, worker } from "@kit.ArkTS";

@Sendable
export class Temp {
  a: number
  b: number

  constructor(a: number, b: number) {
    this.a = a;
    this.b = b;
  }
}
@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  // UI线程和其他两个子线程共享的数据
  private temp = new Temp(10, 20)
  //创建了两个线程
  private addthread = new worker.ThreadWorker('entry/ets/workers/addworker.ets')
  private jianthread = new worker.ThreadWorker('entry/ets/workers/jianworker.ets')
  aboutToAppear(): void {
    // UI线程中接受两个子线程发送的信息
    this.addthread.onmessage = (event: MessageEvents) => {
      console.log('gxxt add ', event.data as number)
      console.log('gxxt 当前的temp值: ',JSON.stringify(this.temp))
    }
    this.jianthread.onmessage = (event: MessageEvents) => {
      console.log('gxxt jian ', event.data as number)
      console.log('gxxt 当前的temp值: ',JSON.stringify(this.temp))
    }
  }

  build() {
    Column({ space: 20 }) {
      Button('加线程')
        .width('60%')
        .onClick(() => {
          this.addthread.postMessageWithSharedSendable(this.temp)
        })
      Button('减线程')
        .width('60%')
        .onClick(() => {
          this.jianthread.postMessageWithSharedSendable(this.temp)
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

项目通过点击两个按钮启动两个线程,并将共享数据temp发送给两个子线程,两个子线程分别执行相加和相减,同时还更新共享数据的原始值,通过观察运算结果和共享数据的变化,我们能掌握worker的开发方式。

运行结果
02-28 09:10:59.798   3292-3292     A03d00/JSAPP     com.gxx.workdemo      I     gxxt add运算结果:  30
02-28 09:10:59.799   3292-3292     A03d00/JSAPP     com.gxx.workdemo      I     gxxt 当前的temp值:  {"a":15,"b":20}
02-28 09:11:04.877   3292-3292     A03d00/JSAPP     com.gxx.workdemo      I     gxxt jian运算结果  5
02-28 09:11:04.877   3292-3292     A03d00/JSAPP     com.gxx.workdemo      I     gxxt 当前的temp值:  {"a":10,"b":20}

刚一开始进行运算的时候add线程面对的a为10,b为20,计算结果为30,add线程同时a=a+5操作,所以此时UI线程得到的a为15;然后jian线程运行结果为|15-20|,jian线程同时a=a-5,所以此时UI线程得到的a为10.


网站公告

今日签到

点亮在社区的每一天
去签到