本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、TaskPool

1. 概念

  • TaskPool 是 ArkTS 提供的多线程环境,用于在后台执行耗时任务

  • 避免阻塞 UI 主线程,提升应用响应速度和用户体验

  • 系统自动管理线程生命周期,使用者无需关心线程创建和销毁

2. 特性

  • 自动线程管理:系统根据任务量自动扩缩容工作线程

  • 任务队列:支持任务提交、执行、取消和优先级设置

  • 结果返回:任务执行完成后将结果返回给宿主线程

二、执行独立的任务

1. 场景

  • 单个独立的耗时计算任务

  • 任务完成后需要将结果返回主线程

  • 如图片加载、数据计算、文件处理等

2. 步骤

步骤1:定义数据模型
// ImageDataModel.ets
export class ImageDataItem {
  imageSrc: string | Resource = '';
  description: string | Resource = '';
  
  constructor(imageSrc: string | Resource = '', description: string | Resource = '') {
    this.imageSrc = imageSrc;
    this.description = description;
  }
}
步骤2:创建并发任务函数
// ImageLoader.ets
import { ImageDataItem } from './ImageDataModel';

// 必须使用 @Concurrent 装饰器标记
@Concurrent
export function loadImageData(itemCount: number): ImageDataItem[] {
  let imageDataList: ImageDataItem[] = [];
  
  // 模拟耗时操作:生成图片数据
  for (let i = 0; i < itemCount; i++) {
    const baseIndex = i * 3;
    
    // 循环使用预定义的图片资源
    imageDataList.push(new ImageDataItem('$media:homeIcon', `图片${baseIndex + 1}`));
    imageDataList.push(new ImageDataItem('$media:profileIcon', `图片${baseIndex + 2}`));
    imageDataList.push(new ImageDataItem('$media:settingsIcon', `图片${baseIndex + 3}`));
  }
  
  return imageDataList;
}
步骤3:在主线程中执行任务
// MainPage.ets
import { taskpool } from '@kit.ArkTS';
import { ImageDataItem } from './ImageDataModel';
import { loadImageData } from './ImageLoader';

@Entry
@Component
struct MainPage {
  @State pageTitle: string = '图片加载示例';
  @State imageList: ImageDataItem[] = [];

  build() {
    Column() {
      Text(this.pageTitle)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })
      
      Button('开始加载图片')
        .fontSize(18)
        .padding(10)
        .onClick(() => {
          this.startImageLoading();
        })
    }
    .padding(20)
    .width('100%')
  }

  private startImageLoading(): void {
    // 创建任务实例,传入任务函数和参数
    const imageLoadTask: taskpool.Task = new taskpool.Task(loadImageData, 25);
    
    // 执行任务并处理结果
    taskpool.execute(imageLoadTask).then((result: object) => {
      // 将结果转换为具体类型
      this.imageList = result as ImageDataItem[];
      
      // 输出日志验证结果
      console.info(`图片数据加载完成,共 ${this.imageList.length} 项`);
      console.info(`第一项描述: ${this.imageList[0]?.description}`);
    }).catch((error) => {
      console.error(`图片加载失败: ${error.message}`);
    });
  }
}

3. 说明

  • taskpool.Task:封装任务函数和参数

  • taskpool.execute():提交任务到线程池执行

  • Promise 结果:通过 then() 回调获取任务执行结果

三、执行多个耗时任务

1. 场景

  • 多个任务需要并行执行

  • 需要等待所有任务完成后统一处理结果

  • 大数据集拆分处理

2. 步骤

步骤1:定义任务函数(复用独立任务的函数)
// ImageLoader.ets
@Concurrent
export function loadImageData(itemCount: number): ImageDataItem[] {
  // 实现同上...
}
步骤2:使用 TaskGroup 管理多个任务
// MultiTaskPage.ets
import { taskpool } from '@kit.ArkTS';
import { ImageDataItem } from './ImageDataModel';
import { loadImageData } from './ImageLoader';

@Entry
@Component
struct MultiTaskPage {
  @State pageTitle: string = '并行图片加载';
  @State combinedImageList: ImageDataItem[] = [];

  build() {
    Column() {
      Text(this.pageTitle)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })
      
      Button('开始并行加载')
        .fontSize(18)
        .padding(10)
        .onClick(() => {
          this.startParallelLoading();
        })
        
      Text(`已加载图片数: ${this.combinedImageList.length}`)
        .fontSize(16)
        .margin({ top: 20 })
    }
    .padding(20)
    .width('100%')
  }

  private startParallelLoading(): void {
    // 创建任务组
    const imageTaskGroup: taskpool.TaskGroup = new taskpool.TaskGroup();
    
    // 添加多个任务到任务组(不同参数)
    imageTaskGroup.addTask(new taskpool.Task(loadImageData, 15));  // 加载75张
    imageTaskGroup.addTask(new taskpool.Task(loadImageData, 10));  // 加载50张  
    imageTaskGroup.addTask(new taskpool.Task(loadImageData, 8));   // 加载40张
    imageTaskGroup.addTask(new taskpool.Task(loadImageData, 12));  // 加载60张

    // 执行任务组
    taskpool.execute(imageTaskGroup).then((results: object) => {
      const taskResults = results as ImageDataItem[][];
      this.processTaskResults(taskResults);
    }).catch((error) => {
      console.error(`并行加载失败: ${error.message}`);
    });
  }

  private processTaskResults(results: ImageDataItem[][]): void {
    // 清空现有数据
    this.combinedImageList = [];
    
    // 合并所有任务的结果
    for (const taskResult of results) {
      this.combinedImageList.push(...taskResult);
    }
    
    // 输出统计信息
    console.info(`并行加载完成,共 ${results.length} 个任务`);
    console.info(`合并后总图片数: ${this.combinedImageList.length}`);
    
    // 验证数据完整性
    let totalFromTasks = 0;
    results.forEach((arr, index) => {
      console.info(`任务${index + 1}加载了 ${arr.length} 张图片`);
      totalFromTasks += arr.length;
    });
    console.info(`各任务图片数总和: ${totalFromTasks}`);
  }
}

3. TaskGroup 的优势

结果返回方式对比:
方式 返回时机 结果格式 适用场景
单个Task 每个任务完成立即返回 单个结果对象 独立任务
TaskGroup 所有任务完成后统一返回 结果数组 需要所有结果的场景
性能优势:
// 大数据处理示例:将10000条数据拆分成多个任务
function processLargeDataset() {
  const totalRecords = 10000;
  const batchSize = 1000;
  const taskGroup = new taskpool.TaskGroup();
  
  // 拆分成10个任务并行处理
  for (let i = 0; i < totalRecords / batchSize; i++) {
    const startIndex = i * batchSize;
    const endIndex = startIndex + batchSize;
    taskGroup.addTask(new taskpool.Task(processDataBatch, startIndex, endIndex));
  }
  
  // 所有批次处理完成后合并结果
  taskpool.execute(taskGroup).then((allResults) => {
    const finalResult = mergeAllResults(allResults);
    console.info(`处理完成,共 ${finalResult.length} 条记录`);
  });
}

四、说明

1. @Concurrent 装饰器

  • 必须使用:在 TaskPool 中执行的函数必须用 @Concurrent 装饰

  • 文件限制:仅支持在 .ets 文件中使用

  • 函数限制:不能访问闭包变量,只能使用局部变量和参数

2. 参数和返回值

  • 序列化要求:参数和返回值必须支持序列化

  • 数据类型:不支持 @State@Prop@Link 等装饰的复杂类型

  • 数据量限制:单次序列化数据量不超过 16MB

五、使用场景

场景特征 使用独立Task 使用TaskGroup
任务数量 单个任务 多个相关任务
结果依赖 任务间无依赖 需要所有任务结果
数据处理 小到中等数据量 大数据集拆分处理
执行时机 立即执行,单独返回 等待全部完成,统一返回

六、总结

TaskPool 的特点:

  1. 提升响应性:将耗时任务移出主线程,避免UI卡顿

  2. 充分利用多核:自动利用设备多核CPU并行处理

  3. 简化开发:无需手动管理线程,专注业务逻辑

  4. 灵活任务管理:支持独立任务和任务组两种模式

选择:

  • 简单任务 → 使用独立 Task

  • 复杂任务 → 使用 TaskGroup 拆分并行处理

  • 需要聚合结果 → 使用 TaskGroup 统一返回

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐