ArkTs-线程池工具封装

写在前面

taskpool工具进行封装,将常用api及异步锁封装进去,减少使用的复杂度。


使用示例

复制代码
// 工具类使用
ThreadUtils.runOnTaskPoolV2({
  taskName: "task_name",
  func: realConcurrentFunc,
  args: [context,
      ...
      ],
  asyncLockKey: 'async_lock_key',
  uiThreadReceiveFunc: uiThreadCallbackFunc,
  sequenceKey: "taskpool_sequence_key"
});


// 实际执行的方法  
@Concurrent
export async function realConcurrentFunc(context: Context,...) {
    ...
}


// 主线程回调方法
function uiThreadCallbackFunc(...) {
    ...
}

参数解析

参数名 类型 含义 默认值 是否必须 注意事项
taskName string 任务名,创建task时传入的变量 '' 非必须传
func Function 真正执行的函数 无默认值 1.必须传,不可为空2.必须为@Concurrent
args Object[] func所需的参数, [] 否,根据func决定 1.参数必须为Sendable2.此处的参数用数组的方式传进来,真正调用func时会将参数一个个传进去。例如:入参为[1, 'hello', context]执行时为func(1, 'hello', context)
asyncLockKey string 异步锁的key '' 1.非必须传,如果不传或传空字符串,则不适用异步锁2.异步锁根据key来管理,需要用到同一个异步锁的传相同的key即可
uiThreadReceiveFunc Function 主线程回调函数 undefined 1.非必须传,需要回调主线程时使用2.调用方式是在func中通过以下方式实现taskpool.Task.sendData(...args)
sequenceKey string task顺序执行的key '' 1.非必须传,需要子线程任务串行执行时使用2.负责执行task的runner,根据sequenceKey来选择;如无执行顺序要求,建议不传或传空字符串

流程图

代码解析

工具类方法封装

1.对传入的参数进行解析,添加默认值

2.因为可以选择是否使用异步锁,封装了一个壳方法进行加锁

3.根据用户选择的使用需要串行执行,选择taskpool or runner

复制代码
    /**
     * 切换至工作线程执行
     *
     * api使用限制:
     * 1.在工作线程执行的函数,必须有@Concurrent注解
     * 2.在工作线程执行的函数,参数必须为可序列化的
     *
     * 如果待执行函数中需要向host线程回调,在task的func中,通过task.sendData(...args: Object[])向host线程发送数据,
     * args为calback所需要的参数。
     *
     * @param taskName 任务名称
     * @param func 子线程待执行方法
     * @param args 子线程待执行方法的参数
     * @param uiThreadReceiveFunc 主线程回调函数
     * @returns
     */
    public static async runOnTaskPoolV2(runOnTaskpoolData: RunOnTaskpoolData): Promise<Object | null | undefined> {
        // 参数校验
        const taskName: string = runOnTaskpoolData.taskName ?? '';
        const func: Function = runOnTaskpoolData.func;
        const args: Object[] = runOnTaskpoolData.args ?? [];
        const asyncLockKey: string = runOnTaskpoolData.asyncLockKey ?? '';
        const uiThreadReceiveFunc: Function | undefined = runOnTaskpoolData.uiThreadReceiveFunc;
        const sequenceKey: string = runOnTaskpoolData.sequenceKey ?? '';

        // 异步锁
        let asyncLock: ArkTSUtils.locks.AsyncLock | null = AsyncLockManager.getInstance().getAsyncLock(asyncLockKey);

        // 构建task
        let bgTask = new taskpool.Task(taskName, shellFunction, [func, args, asyncLock]);

        // 回调函数
        if (uiThreadReceiveFunc) {
            bgTask.onReceiveData(uiThreadReceiveFunc);
        }

        // 判断是否需要顺序执行
        if (StringUtils.isNotEmpty(sequenceKey)) {
            // 需要顺序执行,使用sequenceRunner
            let runner: taskpool.SequenceRunner | undefined = BMThreadUtils.sequenceRunnerRecord[sequenceKey];
            if (!runner) {
                runner = new taskpool.SequenceRunner();
                BMThreadUtils.sequenceRunnerRecord[sequenceKey] = runner;
            }
            return await runner.execute(bgTask);
        } else {
            // 不需要顺序执行,使用普通task
            return await taskpool.execute(bgTask);
        }
    }

壳方法

工具类默认执行的方法,进行异步锁加锁处理后,执行真正的函数func,同时将args从数组参数展开传递给函数

复制代码
/**
 * taskpool中切换至工作线程执行的壳function
 * 1.为方法执行加锁
 *
 * tips:
 *
 * taskpool执行的方法、参数有如下要求:(必须满足,否则执行时会报错)
 * 1.taskpool中传入的function,必须携带@Concurrent注解
 * 2.taskpool中传入的function,参数必须为可序列化的
 *
 * 如果你的方法中需要使用到【调用方】的方法、变量,无法在调用方中声明该方法,会爆出如下错误:
 * "Only imported variablies and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>"
 *
 * 系统组件提供了一些可序列化的方法,涉及到的尽量使用系统api:
 * 1.共享用户首选项
 * 2.可共享的色彩管理
 * 3.基于Sendable对象的图片处理
 * 4.资源管理
 * 5.SendableContext对象管理
 */
@Concurrent
export async function shellFunction(shellFuncArgs: Object[]): Promise<Object | null | undefined> {
    try {
        // 入参
        const func: Function = shellFuncArgs[0] as Function;
        const args: Object[] = shellFuncArgs[1] as Object[];
        const asyncLock: ArkTSUtils.locks.AsyncLock | null = shellFuncArgs[2] as ArkTSUtils.locks.AsyncLock | null;

        // 实际执行的函数
        const executeLogic = async () => {
            return await func(...args);
        };

        // 如果有锁则加锁执行
        if (asyncLock) {
            return await asyncLock.lockAsync(async () => {
                return await executeLogic();
            });
        } else {
            return await executeLogic();
        }
    } catch (error) {
        BMLog.error('ConcurrentFunction', `shellFunction error: code=${error.code}, message=${error.message}`);
    }
    return null;
}

异步锁管理

根据key来管理异步锁,互相影响的任务可传入相同的key,来保证执行顺序

复制代码
/**
 * 异步锁管理器
 *
 * 提供线程池使用的异步锁,保存在主线程中;在主线程调用时获取到,传入子线程使用
 */
export class AsyncLockManager {
    /**
     * 默认线程池的key
     */
    public static readonly KEY_TASKPOOL_DEFAULT: string = "taskPoolDefault";

    /**
     * 线程池异步锁
     */
    public asyncLockRecord: Record<string, ArkTSUtils.locks.AsyncLock> = {};

    private static instance: AsyncLockManager;

    private constructor() {}

    public static getInstance(): AsyncLockManager {
        if (!AsyncLockManager.instance) {
            AsyncLockManager.instance = new AsyncLockManager();
        }
        return AsyncLockManager.instance;
    }

    /**
     * 获取异步锁,当key穿空时返回null
     * @param key 锁的key
     * @returns 异步锁
     */
    public getAsyncLock(key: string = AsyncLockManager.KEY_TASKPOOL_DEFAULT): ArkTSUtils.locks.AsyncLock | null {
        if (BMStringUtils.isEmpty(key)) {
            return null;
        }
        if (!this.asyncLockRecord[key]) {
            this.asyncLockRecord[key] = new ArkTSUtils.locks.AsyncLock();
        }
        return this.asyncLockRecord[key];
    }
}

task执行顺序

taskpool提供了保证task顺序执行的api,需要保证执行顺序的api可传入相同的key

复制代码
    /**
     * 顺序执行任务taskpool
     */
    private static sequenceRunnerRecord: Record<string, taskpool.SequenceRunner> = {};
    
    
        // 判断是否需要顺序执行
        if (BMStringUtils.isNotEmpty(sequenceKey)) {
            // 需要顺序执行,使用sequenceRunner
            let runner: taskpool.SequenceRunner | undefined = BMThreadUtils.sequenceRunnerRecord[sequenceKey];
            if (!runner) {
                runner = new taskpool.SequenceRunner();
                BMThreadUtils.sequenceRunnerRecord[sequenceKey] = runner;
            }
            return await runner.execute(bgTask);
        } else {
            // 不需要顺序执行,使用普通task
            return await taskpool.execute(bgTask);
        }

写在后面

If you like this article, it is written by Johnny Deng.

If not, I don't know who wrote it.

相关推荐
云和数据.ChenGuang7 小时前
鸿蒙智联,极智共生:HarmonyOS与MiniMax智能体的融合新纪元
华为·harmonyos·鸿蒙
UnicornDev9 小时前
【HarmonyOS 6】今日统计卡片实战:运动记录数据概览
华为·harmonyos·arkts·鸿蒙·鸿蒙系统
ShuiShenHuoLe10 小时前
组件的状态ComponentV2
harmonyos·鸿蒙
仓颉编程语言1 天前
CangjieSkills 正式开源:为仓颉 AI 编程打造的“技能增强“方案,实测降低 60% 费用
华为·ai编程·鸿蒙·仓颉编程语言
左手厨刀右手茼蒿2 天前
Flutter 三方库 all_lint_rules_community 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、严谨、基于全量社区 Lint 规则的工业级静态代码质量与安全审计引擎
flutter·harmonyos·鸿蒙·openharmony·all_lint_rules_community
雷帝木木2 天前
Flutter for OpenHarmony:Flutter 三方库 cbor 构建 IoT 设备的极致压缩防窃协议(基于标准二进制 JSON 表达格式)
网络·物联网·flutter·http·json·harmonyos·鸿蒙
王码码20352 天前
Flutter 三方库 servicestack 的鸿蒙化适配指南 - 实现企业级 Message-based 架构集成、支持强类型 JSON 序列化与跨端服务调用同步
flutter·harmonyos·鸿蒙·openharmony·message-based
里欧跑得慢2 天前
Flutter 三方库 jsonata_dart 的鸿蒙化适配指南 - 实现高性能的 JSON 数据查询与转换、支持 JSONata 表达式引擎与端侧复杂数据清洗
flutter·harmonyos·鸿蒙·openharmony·jsonata_dart
国医中兴2 天前
Flutter 三方库 superclass 的鸿蒙化适配指南 - 支持原生高性能类构造、属性代理与深层元数据解析实战
flutter·harmonyos·鸿蒙·openharmony
加农炮手Jinx3 天前
Flutter 组件 ubuntu_service 适配鸿蒙 HarmonyOS 实战:底层系统服务治理,构建鸿蒙 Linux 子系统与守护进程交互架构
flutter·harmonyos·鸿蒙·openharmony·ubuntu_service