开天辟地 HarmonyOS(鸿蒙) - ArkTS 多线程: TaskPool(任务池进阶1)

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - ArkTS 多线程: TaskPool(任务池进阶1)

示例如下:

pages\arkts\concurrent\TaskPoolDemo2.ets

/*
 * TaskPool - 任务池
 *
 * 注:先把 TaskPoolDemo.ets 都看明白,然后再看这个
 */

import { TitleBar, RadioBar, MyLog } from '../../TitleBar';
import { taskpool } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct TaskPoolDemo2 {

  build() {
    Column() {
      TitleBar()
      Tabs() {
        TabContent() { MySample1() }.tabBar('任务执行').align(Alignment.Top)
        TabContent() { MySample2() }.tabBar('任务管理').align(Alignment.Top)
        TabContent() { MySample3() }.tabBar('任务串行').align(Alignment.Top)
        TabContent() { MySample4() }.tabBar('任务组').align(Alignment.Top)
      }
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .layoutWeight(1)
    }
  }
}

@Concurrent
function f1(name: string): string {
  MyLog.d(`f1 ${name}`)
  return `hello:${name}`
}
@Component
struct MySample1 {

  @State message:string = ""

  build() {
    Column({space:10}) {

      /*
       * taskpool - 任务池(多个任务会并行执行)
       *   execute() - 执行指定的函数,并为函数传参
       *   Task() - 指定函数名及其参数,返回一个 taskpool.Task 对象
       *   LongTask() - 指定函数名及其参数,返回一个 taskpool.LongTask 对象,执行此任务的线程会一直存在
       *     也就是说,即使 @Concurrent 不是 async 的,也不会受到 3 分钟的时间限制
       *     即使任务执行完成或取消,任务所属的线程也不会被线程池销毁,只有当调用了 terminateTask() 之后,线程池才会在适当的时候将其销毁
       *   execute() - 执行指定的任务,并指定任务的优先级(Priority 枚举:IDLE, LOW, MEDIUM, HIGH)
       *   executeDelayed() - 延迟执行指定的任务
       *   executePeriodically() - 循环执行指定的任务
       */

      Button('在任务池中执行指定的任务').onClick(() => {
        // 执行指定的 @Concurrent 函数,并传参
        taskpool.execute(f1, "webabcd").then((value) => {
          // 获取函数的返回值
          this.message += `result ${value}\n`
        })
      })

      Button('在任务池中执行指定的任务,并指定任务的优先级').onClick(() => {
        // 实例化任务(指定任务的 @Concurrent 函数,并传参)
        let task1: taskpool.Task = new taskpool.Task(f1, "aaa");
        let task2: taskpool.Task = new taskpool.Task(f1, "bbb");
        let task3: taskpool.Task = new taskpool.Task(f1, "ccc");
        let task4: taskpool.Task = new taskpool.Task(f1, "ddd");
        // 执行指定的任务,并指定任务的优先级
        taskpool.execute(task1, taskpool.Priority.IDLE).then((value) => {
          // 获取任务的 @Concurrent 函数的返回值
          this.message += `result(idle) ${value}\n`
        });
        taskpool.execute(task2, taskpool.Priority.LOW).then((value) => {
          this.message += `result(low) ${value}\n`
        });
        taskpool.execute(task3, taskpool.Priority.MEDIUM).then((value) => {
          this.message += `result(medium) ${value}\n`
        });
        taskpool.execute(task4, taskpool.Priority.HIGH).then((value) => {
          this.message += `result(high) ${value}\n`
        });
      })

      Button('执行长时任务,且任务所属的线程一直存在').onClick(() => {
        // 执行此任务的线程一直存在(也就是说,即使 @Concurrent 不是 async 的,也不会受到 3 分钟的时间限制)
        let task: taskpool.LongTask = new taskpool.LongTask(f1, "webabcd");
        taskpool.execute(task).then((value) => {
          this.message += `result ${value}\n`
        });
      })

      Button('延迟执行任务').onClick(() => {
        let task: taskpool.Task = new taskpool.Task(f1, "webabcd");
        // 1000 毫秒后执行指定的任务
        taskpool.executeDelayed(1000, task, taskpool.Priority.IDLE).then((value) => {
          this.message += `result ${value}\n`
        }).catch((e: BusinessError) => {
          this.message += `error ${e.message}\n`
        })
      })

      Button('循环执行任务').onClick(() => {
        let task: taskpool.Task = new taskpool.Task(f1, "webabcd");
        // 1000 毫秒后执行指定的任务,然后每 1000 毫秒再执行一次此任务
        taskpool.executePeriodically(1000, task, taskpool.Priority.IDLE);
      })

      Scroll() {
        Text(this.message)
      }.layoutWeight(1).align(Alignment.TopStart).backgroundColor(Color.Yellow).width('100%')
    }
  }
}

@Concurrent
async function f2(name: string): Promise<string> {
  let t: number = Date.now();
  while (Date.now() - t < 10000) {
    await new Promise<void>((r) => { setTimeout(r, 500) })
    MyLog.d(`f2 ${name} running`)
    // 任务如果在运行中被取消的话,只是不再等待任务返回了,但是任务对应的函数仍然会继续执行,直到执行完毕为止
    // 所以建议在这里判断任务是否被取消了,如果被取消了,则不需要再执行后续逻辑了
    if (taskpool.Task.isCanceled()) {
      MyLog.d(`f2 ${name} isCanceled`)
      break
    }
    continue;
  }
  return `hello:${name}`
}
@Component
struct MySample2 {

  @State message:string = ""
  task: taskpool.Task = new taskpool.Task(f2, "webabcd");
  longTask: taskpool.LongTask = new taskpool.LongTask(f2, "wanglei");

  build() {
    Column({space:10}) {

      /*
       * taskpool - 任务池
       *   isConcurrent() - 用于判断指定的函数是否是 @Concurrent 装饰的
       *   getTaskPoolInfo() - 获取当前的任务池的信息(返回一个 TaskPoolInfo 对象)
       *     threadInfos - 任务池中的全部线程的信息,返回一个 ThreadInfo 对象数组
       *       tid - 此线程的 id
       *       taskIds - 此线程中的全部任务的 id 集合
       *       priority - 此线程的优先级(Priority 枚举:IDLE, LOW, MEDIUM, HIGH)
       *     taskInfos - 任务池中的全部任务的信息,返回一个 TaskInfo 对象数组
       *       id - 此任务的 id
       *       name - 此任务的对应的 @Concurrent 函数的名称
       *       duration - 此任务到目前为止的执行的时长(单位:毫秒)
       *       state - 此任务的状态(State 枚举:WAITING, RUNNING, CANCELED)
       *   cancel() - 取消指定的任务
       *     任务如果还未执行,就不再执行了
       *     任务如果执行完了,就会抛出异常
       *     任务如果执行中,则不会在等待其返回结果,但是任务对应的函数会继续执行(建议在函数中判断 taskpool.Task.isCanceled() 如果被取消了则退出即可)
       *   terminateTask() - 终止指定的长时任务(即告诉任务池,此线程在适当的时候可以被销毁了)
       *     建议长时任务执行完成后调用此方法,如果不调用的话,此长时任务所属的线程将永远都不会被任务池销毁
       *
       * taskpool.Task, taskpool.LongTask - 任务对象
       *   实例方法 isDone() - 此任务是否执行完成了
       *   类方法 isCanceled() - 当前任务是否被取消了
       */

      Button('执行任务').onClick(() => {
        // 执行一个任务
        taskpool.execute(this.task).then((value) => {
          this.message += `result ${value}\n`
        });
        // 执行一个长时任务
        taskpool.execute(this.longTask).then((value) => {
          this.message += `result ${value}\n`
        });
      })

      Button('获取任务信息').onClick(() => {
        this.message += `f2 isConcurrent:${taskpool.isConcurrent(f2)}\n`
        this.message += `task isDone:${this.task.isDone()}\n`
        this.message += `longTask isDone:${this.longTask.isDone()}\n`
      })

      Button('获取任务池信息').onClick(() => {
        let info: taskpool.TaskPoolInfo = taskpool.getTaskPoolInfo();
        let threadInfos = Array.from(info.threadInfos)
        for (let threadInfo of threadInfos) {
          this.message += `threadId:${threadInfo.tid}, taskIds:${threadInfo.taskIds?.join("|")}, priority:${threadInfo.priority}\n`
        }
        let taskInfos = Array.from(info.taskInfos)
        for (let taskInfo of taskInfos) {
          this.message += `taskId:${taskInfo.taskId}, name:${taskInfo.name}, duration:${taskInfo.duration}, state:${taskInfo.state}\n`
        }
      })

      Button('取消任务').onClick(() => {
        try {
          // 取消指定的任务
          taskpool.cancel(this.task);
        } catch (e) {
          // 任务如果已经执行完了,则取消时就会抛出异常
          this.message += `task cancel error, errCode:${e.code}, errMessage:${e.message}`;
        }

        try {
          // 取消指定的任务
          taskpool.cancel(this.longTask);
          // 终止指定的长时任务(即告诉任务池,此线程在适当的时候可以被销毁了)
          taskpool.terminateTask(this.longTask);
        } catch (e) {
          // 任务如果已经执行完了,则取消时就会抛出异常
          this.message += `longTask cancel error, errCode:${e.code}, errMessage:${e.message}`;
        }
      })

      Scroll() {
        Text(this.message)
      }.layoutWeight(1).align(Alignment.TopStart).backgroundColor(Color.Yellow).width('100%')
    }
  }
}

@Concurrent
async function f3(name: string): Promise<string> {
  await new Promise<void>((r) => { setTimeout(r, 1000) })
  return `hello:${name}`
}
@Component
struct MySample3 {

  @State message:string = ""

  build() {
    Column({space:10}) {

      /*
       * taskpool.SequenceRunner - 串行任务管理器
       *   constructor() - 通过构造函数指定串行任务管理器的名称和优先级,返回一个 taskpool.SequenceRunner 对象
       *   execute() - 执行指定的任务,多个任务会串行执行
       *
       * 注:用 taskpool 的 execute() 执行的多个任务会并行执行
       */

      Button('串行执行任务').onClick(async () => {
        let task1:taskpool.Task = new taskpool.Task(f3, "aaa");
        let task2:taskpool.Task = new taskpool.Task(f3, "bbb");
        let task3:taskpool.Task = new taskpool.Task(f3, "ccc");
        // 指定串行任务管理器的名称和优先级,返回一个 taskpool.SequenceRunner 对象
        let sequenceRunner:taskpool.SequenceRunner = new taskpool.SequenceRunner("mySequenceRunner", taskpool.Priority.HIGH);
        // 执行 task1
        sequenceRunner.execute(task1).then((value) => {
          this.message += `task1 result ${value}\n`;
        });
        // task1 执行完成后才会执行 task2
        sequenceRunner.execute(task2).then((value) => {
          this.message += `task2 result ${value}\n`;
        });
        // task2 执行完成后才会执行 task3
        let result = await sequenceRunner.execute(task3);
        this.message += `task3 result ${result}\n`;
      })

      Scroll() {
        Text(this.message)
      }.layoutWeight(1).align(Alignment.TopStart).backgroundColor(Color.Yellow).width('100%')
    }
  }
}

@Concurrent
async function f4(name: string): Promise<string> {
  await new Promise<void>((r) => { setTimeout(r, 3000) })
  return `hello:${name}`
}
@Component
struct MySample4 {

  @State message:string = ""
  taskGroup?: taskpool.TaskGroup;

  build() {
    Column({space:10}) {

      /*
       * taskpool - 任务池
       *   TaskGroup() - 指定任务组名称,返回一个 taskpool.TaskGroup 对象
       *   addTask() - 添加任务(可以指定一个 @Concurrent 函数并为函数传参,或者指定一个 taskpool.Task 对象)
       *   execute() - 并行执行指定的任务组中的所有任务
       *     任务全部成功,则任务组成功
       *     如果有失败的任务,则抛出第一个失败的任务的异常
       */
      Button('执行任务组').onClick(async () => {
        this.taskGroup = new taskpool.TaskGroup("myTaskGroup");
        this.taskGroup.addTask(f4, "aaa");
        this.taskGroup.addTask(new taskpool.Task(f4, "bbb"));
        this.taskGroup.addTask(f4, "ccc");
        taskpool.execute(this.taskGroup, taskpool.Priority.HIGH).then((array: Array<Object>) => {
          // 返回的数据是每个任务的执行结果的列表,顺序与 addTask() 的顺序是一样的
          array.forEach((value, index) => {
            this.message += `task index:${index}, result:${value}\n`
          });
        })
      })

      Button('取消任务').onClick(async () => {
        try {
          // 取消指定的任务组(关于任务组的取消请参见上面的 MySample2 中的说明)
          taskpool.cancel(this.taskGroup);
        } catch (e) {
          this.message += `task cancel error, errCode:${e.code}, errMessage:${e.message}`;
        }
      })

      Scroll() {
        Text(this.message)
      }.layoutWeight(1).align(Alignment.TopStart).backgroundColor(Color.Yellow).width('100%')
    }
  }
}

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @ 2025-02-05 13:46  webabcd  阅读(90)  评论(0)    收藏  举报