鸿蒙NEXT开发【应用并发设计】应用架构

简介

ArkTS是HarmonyOS APP的开发语言,它在保持TypeScript(简称TS)基本语法风格的基础上,一方面规范强化静态检查提升开发者代码的规范性;另一方面基于TypeScript增强了一些特性提升开发体验和执行效率,尤其是在并发能力上的提升。

本文档主要面向HarmonyOS APP的设计人员或开发人员,介绍应用在并行任务方案设计过程中,可能会遇到的典型场景以及对应的推荐设计方案,同时给出了方案的关键点及参考案例。

典型业务场景

根据当前HarmonyOS APP开发过程中遇到的实际并发业务场景,总结提炼出如下典型场景,可供更多APP参考,设计其并发业务方案。

场景编号 场景分类 场景名称 简述
1 并发能力选择 耗时任务并发执行 相对独立的耗时任务需要放到单独的子线程中执行,推荐TaskPool
2 常驻任务并发执行 常驻的耗时任务需要放到单独的子线程中执行,推荐Worker
3 共享内存并发业务 开发常见的共享内存并发业务,推荐使用TaskPool和Worker的API进行开发
4 长时任务并发执行 长时间运行的任务,不独占线程执行,推荐TaskPool长时任务
5 并发任务管理 多任务关联执行(串行顺序依赖) 有严格执行顺序的任务,不希望并发执行
6 多任务关联执行(树状依赖) 待执行的任务存在依赖关系,等待被依赖执行完再调度
7 多任务同步等待结果(任务组) 多个关联的任务需要等待全部结果返回后再进行后续操作
8 多任务优先级调度 不同任务设置不同的优先级
9 任务延时调度 任务不希望立即执行,希望延时一定时间后调度
10 线程间通信 同语言线程间通信(ArkTS内) 介绍ArkTS线程间的通信机制
11 跨语言多线程通信(C++与ArkTS) 介绍C++与ArkTS线程间的通信机制
12 线程间模块共享(单例模式) 介绍进程内单例场景的实现方式
13 线程间不可变数据共享 介绍不可变数据共享场景的实现方式
14 生产者与消费者模式 介绍生产者与消费者模式场景的实现方式

并发能力整体架构

并发能力概述

并发能力框架如下:

1

  • 主线程: 执行UI业务、不耗时操作、单次I/O任务,与其他ArkTS线程共享系统I/O线程池,不阻塞当前ArkTS线程。

  • TaskPool 高并发任务池: 执行耗时任务,基于TaskPool封装任务执行的入口,可统计模块负载,开发者无需管理线程实例的生命周期。

  • Worker 线程: 执行常驻任务,CPU密集型、耗时任务,当前限制线程个数为64。

  • FFRT 任务池:

    1. 系统任务:系统分发到FFRT线程的业务,例如异步I/O任务等,开发者无需关注;
    2. 用户任务:开发者创建的C/C++耗时任务,支持负载均衡及线程生命周期管理等能力。
  • Pthread 线程: 采用C/C++开发的模块,需要后台运行或者耗时的ArkTS无关业务,不限制线程个数。

并发模型与业界模型的差异

共享内存并发模型

2

共享内存模型指的是采用线程和锁的并发模型,不同线程之间共享内存,通过锁来进行临界区保护。对于不同业务,如果包含I/O操作或者锁,为了业务不被阻塞,需要开启多个线程来执行不同的业务,线程情况如下图所示:

3

因此,应用上经常存在几百个线程,增加了调度开销和内存占用。

ArkTS并发模型

4

ArkTS采用了内存隔离的线程模型,不同线程之间通过消息通信,线程内无锁化运行。对于不同业务,其内部的I/O操作会由系统分发到后台的I/O任务池,不阻塞ArkTS上层逻辑,线程情况如下图所示:

5

异步I/O不阻塞ArkTS线程,同时TaskPool及I/O线程池由系统管理,提升能效。

ArkTS语言支持了TaskPool和Worker的并发能力,接下来简单介绍TaskPool和Worker的功能。

TaskPool提供了任务分发的入口,支持将任务分发到不同优先级的队列,TaskPool底层自动管理了一定数量的工作线程,会从队列获取任务执行。同时,工作线程会根据任务数量进行自动扩缩容,保证任务执行效率。TaskPool内部会根据任务量及当前线程数量,决定是否扩容或缩容,当任务较多时会扩容。线程的上限跟硬件核数相关,例如8核设备,线程数上限大概为7-15左右。

空任务的Worker线程的内存占用大约2MB左右,因此需要控制线程的数量,避免内存过大。

ArkTS与传统共享内存并行化的差异

通过上述并发模型的对比,可以看出在ArkTS中的异步I/O操作,会分发到I/O任务池中,不阻塞ArkTS语言的执行。而Java需要大量线程进行阻塞I/O操作,导致线程数较多。

其次,ArkTS采用内存隔离的并发模型,不能跨线程共享对象,需要进行线程间数据通信。而Java可以直接访问不同线程的对象,但是需要使用锁进行数据的线程安全保护。

并发能力选择

概述

不同的业务场景用到的并发能力各不相同,此章节对常见的业务场景进行分类,并分别介绍各类业务场景的HarmonyOS APP开发方案设计。

耗时任务并发执行场景

  • 场景描述

    在应用业务实现过程中,对于相对独立的耗时任务,如果放在主线程中执行会阻塞主线程的UI业务,出现卡顿丢帧等影响用户体验的问题。通常需要将这个独立的耗时任务放到单独的子线程中执行。典型的耗时任务有CPU密集型任务、I/O密集型任务以及同步任务。

    常见的业务场景如下所示:

    常见业务场景 具体业务描述 场景类型
    CPU密集型 I/O密集型 同步任务
    图片/视频编解码 将图片或视频进行编解码再展示 ×
    压缩/解压缩 对本地压缩包进行解压操作,或者本地文件的压缩操作 ×
    JSON解析 对JSON字符串的序列化和反序列化操作 × ×
    模型运算 对数据进行模型运算分析等 × ×
    网络下载 密集网络请求下载资源、图片、文件等 × ×
    数据库操作 将聊天记录、页面布局信息、音乐列表信息等保存到数据库,或者应用二次启动时,读取数据库展示相关信息 × ×

    上述业务场景均为独立的耗时任务,任务执行周期短,跟外部交互较少,只包含有限的输入和输出,分发到后台线程执行后再获取结果。这些类型的任务使用TaskPool可以简化开发工作量,避免管理复杂的生命周期,避免线程泛滥,开发者只需要将上述独立的任务放入TaskPool队列,再等待结果即可。

  • 实现方案介绍

    ArkTS提供了任务池(TaskPool)的并发能力,可以将独立的耗时任务分发到子线程中执行,满足上述业务场景并行化执行的诉求,开发者只需要如下三个步骤即可完成任务并发编程。实现方案介绍:

    步骤一:将需要在子线程执行的任务封装成一个@Concurrent修饰的函数;

    步骤二:通过TaskPool的任务执行接口将任务分发到子线程;

    步骤三:异步执行结束后在宿主线程接收结果,进行后续处理。

  • 业务实现中的关键点

    1. TaskPool中执行的任务需要考虑通信开销

      由于TaskPool底层采用内存隔离的并发模型,对象的跨线程传输存在性能开销,需要控制线程间传递对象的大小及交互频率(200KB的典型耗时约1ms)

    2. TaskPool中执行的任务不能因阻塞,导致执行时间过长(非异步耗时不超过3分钟)

      由于执行时间较长的任务会占据任务池中的线程,导致其他任务没有空闲线程调度,因此对于一直占据任务线程执行超过3分钟的任务,系统会进行回收。

      网络下载、文件访问等异步I/O操作系统会分发到I/O线程池,不受上面规则约束。

    3. TaskPool中执行的任务不能有上下文依赖

      由于TaskPool任务会在子线程中执行,与宿主线程上下文环境存在差异,因此需要保证任务的独立性,内部实现只能依赖模块化导入或者参数传入。

  • 案例参考

import { taskpool } from '@kit.ArkTS';

@Concurrent
async function foo(a: number, b: number) {
  return a + b;
}

taskpool.execute(foo, 1, 2).then((ret: Object) => { // 结果处理
  console.log('Return:' + ret);
})
  • 与业界方案特殊差异说明

    业界均采用线程池方案,与TaskPool无特殊差异。

  • 不推荐应用实现方式

    对于独立的耗时任务,不建议采用Worker来实现。

常驻任务并发执行场景

  • 场景描述

    在应用业务实现过程中,对于一些长耗时(大于3min)且并发量不大的常驻任务场景,使用Worker在后台线程中运行这些耗时逻辑,避免阻塞主线程而导致出现丢帧卡顿等影响用户体验性的问题 。

    常驻不是指可以在后台保活运行的任务,而是相比于短时任务,时间更长的任务,可能与主线程生命周期一致。

    常见的业务场景如下所示:

    常见业务场景 具体业务描述 场景类型
    游戏中台场景 启动子线程作为游戏业务的主逻辑线程,UI线程只负责渲染 常驻任务
    产线硬件压测 需要阻塞调用硬件能力,做老化测试,阻塞式 阻塞任务
  • 实现方案介绍

    ArkTS提供了Worker的并发能力,支持Worker线程与宿主线程之间进行通信,开发者需要主动创建或关闭Worker线程。实现方案介绍:

    步骤一:创建Worker对象;

    步骤二:在Worker线程中绑定Worker对象,并处理需要在子线程执行的逻辑;

    步骤三:宿主线

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值