实现多线程并发功能鸿蒙示例代码 原创

鸿蒙场景化示例代码技术工程师
发布于 2025-2-27 15:55
浏览
0收藏

本文原创发布在华为开发者社区

介绍

TaskPool和Worker均支持多线程并发能力。

  • TaskPool的工作线程会绑定系统的调度优先级,并且支持负载均衡(自动扩缩容);
  • Worker需要开发者自行创建,存在创建耗时以及不支持设置调度优先级;
  • 性能方面使用TaskPool会优于Worker,因此大多数场景推荐使用TaskPool。

本示例分别利用TaskPool和Worker开发多线程并发场景,以此来展示两者的不同之处以及相似之处。

实现多线程并发功能源码链接

效果预览

实现多线程并发功能鸿蒙示例代码-鸿蒙开发者社区

使用说明

  1. 进入应用会看到消息列表,消息实时刷新。
  2. 点击任一消息进入对话框,点击下载按钮可将文件下载保存到本地。

实现思路

  1. aboutToAppear,在组件即将出现时被调用,用于执行初始化、数据准备操作。
  • workerInstance.postMessage,向workerInstance发送一条消息,消息是一个对象,包含type属性设置为true和context属性设置为this.context。使用postMessage方法将消息发送给Web Worker,用于开启子线程任务,并且可以根据业务需求传递自定义的上下文信息。
  • workerInstance.onmessage ,workerInstance注册一个消息处理函数,当从子线程接收到消息时会调用该函数。
  • let newMessage: string = e.data.toString();:将接收到的数据(e.data)转换为字符串类型,并存储在 newMessage 变量中。
  aboutToAppear(): void { 
    workerInstance.postMessage({ type: true, context: this.context }) 
    workerInstance.onmessage = (e) => {
      let newMessage: string = e.data.toString();
      console.info("page received message:" + newMessage)
      if (!this.messageArr.includes(newMessage)) {
        this.messageArr.unshift(newMessage);
      }
      console.info("page received message:" + JSON.stringify(this.messageArr))
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  1. 在每个页面点击下载后,执行以下操作:
  • 创建一个taskpool.Task对象task,将downloadFile函数作为任务,使用this.params.name 作为任务名称,指定一个文件的下载链接,并传入this.context作为任务的上下文。

  • 为emitter对象注册event事件的监听器,在事件触发时,从eventData中提取progress信息。

  • 打印下载进度信息到控制台。

  • 当进度达到 100 时,使用 promptAction.showToast 显示一个下载完成的提示,位置在底部 100 像素处。

    这里使用了TaskPool方式,这种方式偏向独立任务维度,该任务在线程中执行,无需关注线程的生命周期,超长任务(大于3分钟)会被系统自动回收。

    let task = new taskpool.Task(downloadFile, this.params.name,
    "", this.context);
    emitter.on(event, (eventData) => {
    let progress: number = eventData.data?.progress;
    console.info('receive download progress:' + progress);
    if (progress == 100) {
        promptAction.showToast({ message: `下载完成`, bottom: 100 });
     }
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  1. 构造messageReceive()函数,调用systemDateTime.getCurrentTime()方法获取当前时间,使用await等待结果并存储在time变量中。将获取到的当前时间打印到控制台。检查time是否是5000的倍数,如果是,则返回一个字符串name-${time},否则返回一个空字符串。
export async function messageReceive(): Promise<string> {
  let time = await systemDateTime.getCurrentTime()
  console.info(`Succeeded in getting currentTime : ${time}`);
  if (time % 5000 === 0) {
    return `name-${time}`
  } else {
    return '';
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  1. 为workerPort的onmessage事件添加一个异步处理函数,当接收到消息时会执行以下操作:
  • 打印execute worker task到控制台。

  • 从e.data.type中获取flag并将其转换为布尔类型,用于控制while循环。

  • 当flag为true时,进入while循环。

  • 在循环中调用messageReceive函数获取消息,并使用await等待结果。

  • 如果receiveMessage不为空,打印消息并使用workerPort.postMessage将消息发送回宿主线程。

    这里使用了Worker方式,这种方式偏向线程的维度,支持长时间占据线程执行,需要主动管理线程生命周期。

workerPort.onmessage = async (e: MessageEvents) => {
  console.log("execute worker task")
  let flag = e.data.type as Boolean;
  while (flag) {
    let receiveMessage = await messageReceive();

    if (receiveMessage) {
      console.info("success get message: " + receiveMessage)
      workerPort.postMessage(receiveMessage);
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2025-2-28 14:49:27修改
收藏
回复
举报


回复
    相关推荐