当前位置: 首页 > news >正文

鸿蒙开发——线程内通信

1、概 述

在介绍鸿蒙开发中线程间通信问题前,我们先解释下什么是线程。

在计算机科学中,线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。这么说是不是太抽象了?咱们换成通俗的话来说:

假如把一个正在运行的程序想象成一个大工厂。这个工厂在运作的时候,有很多不同的任务要做。线程呢,就像是工厂里的一个的工人小组(不同的科室)。

每个工人小组(线程)都可以独立地干活,去完成特定的一小部分任务。比如有的工人小组专门负责把原材料搬进工厂,有的专门负责在生产线上组装零件,还有的专门负责把成品打包运出去。

这些工人小组可以同时工作,一起努力让工厂的生产效率更高。就像在电脑里,多个线程可以同时进行不同的任务,让程序运行得更快更顺畅。

这些工人小组都是在同一个大工厂(程序)里干活,他们可以共享一些工厂里的资源,比如工具啊、仓库啊之类的。这样就可以更方便地协同工作啦。

相应的,我们通过上面的形象的例子了解了什么是线程后,那线程内通信,就可以类比为工人小组之间的消息传递。

2、线程模型

在介绍线程内通信前,我们先了解下鸿蒙应用的线程主要有哪几类,主要分为三类,他们分别的职责说明如下:

1)主线程

  • 执行UI绘制。

  • 管理主线程的ArkTS引擎实例,使多个UIAbility组件能够运行在其之上。

  • 管理其他线程的ArkTS引擎实例,例如使用TaskPool(任务池)创建任务或取消任务、启动和终止Worker线程。

  • 分发交互事件。

  • 处理应用代码的回调,包括事件处理和生命周期管理。

  • 接收TaskPool以及Worker线程发送的消息。

2)TaskPool Worker线程

  • 用于执行耗时操作,支持设置调度优先级、负载均衡等功能,推荐使用。

3)Worker线程

  • 用于执行耗时操作,支持线程间通信。

TaskPool(任务池)和Worker的作用是为应用程序提供一个多线程的运行环境,用于处理耗时的计算任务或其他密集型任务。可以有效地避免这些任务阻塞主线程,从而最大化系统的利用率,降低整体资源消耗,并提高系统的整体性能。

❓ TaskPool Worker和Worker他们的区别是什么呢?

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

TaskPool偏向独立任务维度,该任务在线程中执行,无需关注线程的生命周期,超长任务(大于3分钟且非长时任务)会被系统自动回收;而Worker偏向线程的维度,支持长时间占据线程执行,需要主动管理线程生命周期。

常见的一些开发场景及适用场景说明如下:

  • 运行时间超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时)的任务【例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker】。

  • 有关联的一系列同步任务。例如在一些需要创建、使用句柄的场景中,句柄创建每次都是不同的,该句柄需永久保存,保证使用该句柄进行操作,需要使用Worker。

  • 需要设置优先级的任务。例如图库直方图绘制场景,后台计算的直方图数据会用于前台界面的显示,影响用户体验,需要高优先级处理,需要使用TaskPool。

  • 需要频繁取消的任务。例如图库大图浏览场景,为提升体验,会同时缓存当前图片左右侧各2张图片,往一侧滑动跳到下一张图片时,要取消另一侧的一个缓存任务,需要使用TaskPool。

  • 大量或者调度点较分散的任务。例如大型应用的多个模块包含多个耗时任务,不方便使用Worker去做负载管理,推荐采用TaskPool。

【TaskPool和Worker的使用,未来如果有必要再展开讨论】

3、线程内通信

EventHub提供了线程内发送和处理事件的能力,包括对事件订阅、取消订阅、触发事件等。

在基类Context中提供了EventHub对象,可以通过发布订阅方式来实现事件的传递。在事件传递前,订阅者需要先进行订阅,当发布者发布事件时,订阅者将接收到事件并进行相应处理。

EventHub对象比较简单,主要提供了三个方法,如下:

// 订阅指定事件on(event: string, callback: Function): void;// 取消订阅事件off(event: string, callback?: Function): void;// 触发指定事件emit(event: string, ...args: Object[]): void;

使用方法以UIAbility组件实例内通信为例:

👉🏻 step 1: 

在UIAbility中调用eventHub.on()方法注册一个自定义事件“event1”,eventHub.on()有如下两种调用方式,使用其中一种即可(由于this指向问题,推荐使用箭头函数的方式注册)。​​​​​​​

import { hilog } from '@kit.PerformanceAnalysisKit';import { UIAbility, Context, Want, AbilityConstant } from '@kit.AbilityKit';const DOMAIN_NUMBER: number = 0xFF00;const TAG: string = '[EventAbility]';export default class EntryAbility extends UIAbility {  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {    // 获取eventHub    let eventhub = this.context.eventHub;    // 执行订阅操作    eventhub.on('event1', this.eventFunc);    eventhub.on('event1', (data: string) => {      // 触发事件,完成相应的业务操作    });    hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onCreate');  }  // ...  eventFunc(argOne: Context, argTwo: Context): void {    hilog.info(DOMAIN_NUMBER, TAG, '1. ' + `${argOne}, ${argTwo}`);    return;  }}

👉🏻 step 2: 

在UI中通过eventHub.emit()方法触发该事件,在触发事件的同时,根据需要传入参数信息。​​​​​​​

import { common } from '@kit.AbilityKit';import { promptAction } from '@kit.ArkUI';@Entry@Componentstruct Page_EventHub {  private context = getContext(this) as common.UIAbilityContext;  eventHubFunc(): void {    // 不带参数触发自定义“event1”事件    this.context.eventHub.emit('event1');    // 带1个参数触发自定义“event1”事件    this.context.eventHub.emit('event1', 1);    // 带2个参数触发自定义“event1”事件    this.context.eventHub.emit('event1', 2, 'test');    // 开发者可以根据实际的业务场景设计事件传递的参数  }  build() {    Column() {      // ...      List({ initialIndex: 0 }) {        ListItem() {          Row() {            // ...          }          .onClick(() => {            this.eventHubFunc();            promptAction.showToast({              message: 'EventHubFuncA'            });          })        }        // ...        ListItem() {          Row() {            // ...          }          .onClick(() => {            this.context.eventHub.off('event1');            promptAction.showToast({              message: 'EventHubFuncB'            });          })        }        // ...      }      // ...    }    // ...  }}

👉🏻 step 3: 

在自定义事件“event1”使用完成后,可以根据需要调用eventHub.off()方法取消该事件的订阅。​​​​​​​

import { UIAbility } from '@kit.AbilityKit';export default class EntryAbility extends UIAbility {  // ...   onDestroy(): void {    this.context.eventHub.off('event1');  }}

示例中的代码,在UIAbility的注册事件回调中可以得到对应的触发事件结果,运行日志结果如下所示。​​​​​​​

[Example].[Entry].[EntryAbility] 1. [][Example].[Entry].[EntryAbility] 1. [1][Example].[Entry].[EntryAbility] 1. [2,"test"]

http://www.mrgr.cn/news/66467.html

相关文章:

  • springboot集成onlyoffice(部署+开发)
  • 如何对LabVIEW软件进行性能评估?
  • DiskGenius工具扩容Mac OS X Apple APFS分区
  • 数据结构——二叉树(续集)
  • 无人机之中继通信技术篇
  • 使用AWS Lambda构建无服务器应用程序
  • Vue:事件
  • CentOS操作系统安装过程简介
  • C++ 并发专题 - 无锁数据结构(队列)
  • 2025年知识管理新方案:十款前沿知识库搭建工具详解
  • Spring事务详解
  • 基数排序算法
  • Linux系统编程——线程概述、线程控制和线程私有数据
  • 如何高效集成每刻与金蝶云星空的报销单数据
  • 代码随想录一刷——454.四数相加II
  • Jest进阶知识:测试快照 - 确保组件渲染输出正确
  • 2024年专业的10款数据恢复工具你都用过哪些?
  • 鸿蒙应用开发:下载功能
  • 【020】基于51单片机病房呼叫系统
  • 105. UE5 GAS RPG 搭建主菜单
  • Qt 环境实现视频和音频播放
  • 负载均衡与容错的基本原则
  • C#-类:索引器
  • 【xml转JSON】
  • windows_worm
  • 信号与噪声分析——第三节:随机过程的统计特征