HarmonyOS开发-多线程与异步编程

问题描述

在HarmonyOS应用中如何实现多线程处理?如何使用Worker、TaskPool和异步编程避免UI卡顿?

关键字 : Worker TaskPool 异步编程 Promise 多线程


解决方案

1. Worker线程基础

typescript 复制代码
import worker from '@ohos.worker'

// 主线程代码
@Entry
@Component
struct WorkerDemo {
  @State result: string = ''
  @State isProcessing: boolean = false
  private workerInstance?: worker.ThreadWorker

  aboutToAppear() {
    this.createWorker()
  }

  aboutToDisappear() {
    this.destroyWorker()
  }

  build() {
    Column({ space: 16 }) {
      Text('Worker多线程')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Button('开始计算')
        .width('100%')
        .enabled(!this.isProcessing)
        .onClick(() => {
          this.startHeavyTask()
        })

      if (this.isProcessing) {
        Row({ space: 8 }) {
          LoadingProgress()
            .width(20)
            .height(20)
          Text('计算中...')
        }
      }

      if (this.result) {
        Text('结果:')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
        Text(this.result)
          .fontSize(14)
          .fontColor('#1890ff')
      }
    }
    .padding(16)
  }

  private createWorker() {
    try {
      // 创建Worker实例
      this.workerInstance = new worker.ThreadWorker('entry/ets/workers/TaskWorker.ts')

      // 监听Worker消息
      this.workerInstance.onmessage = (event) => {
        console.log('收到Worker消息:', event.data)
        this.result = event.data
        this.isProcessing = false
      }

      // 监听Worker错误
      this.workerInstance.onerror = (error) => {
        console.error('Worker错误:', error.message)
        this.isProcessing = false
      }
    } catch (error) {
      console.error('创建Worker失败:', error)
    }
  }

  private startHeavyTask() {
    if (!this.workerInstance) return

    this.isProcessing = true
    this.result = ''

    // 向Worker发送消息
    this.workerInstance.postMessage({
      type: 'calculate',
      data: {
        start: 1,
        end: 1000000
      }
    })
  }

  private destroyWorker() {
    if (this.workerInstance) {
      this.workerInstance.terminate()
      this.workerInstance = undefined
    }
  }
}

// Worker线程代码
// entry/ets/workers/TaskWorker.ts
import worker from '@ohos.worker'

const workerPort = worker.workerPort

// 监听主线程消息
workerPort.onmessage = (event) => {
  console.log('Worker收到消息:', event.data)

  const { type, data } = event.data

  if (type === 'calculate') {
    // 执行耗时计算
    const result = calculateSum(data.start, data.end)

    // 发送结果回主线程
    workerPort.postMessage(`计算结果: ${result}`)
  }
}

function calculateSum(start: number, end: number): number {
  let sum = 0
  for (let i = start; i <= end; i++) {
    sum += i
  }
  return sum
}

// 监听错误
workerPort.onerror = (error) => {
  console.error('Worker内部错误:', error.message)
}

2. TaskPool任务池

typescript 复制代码
import taskpool from '@ohos.taskpool'

// 定义并发函数
@Concurrent
function processLargeData(data: number[]): number[] {
  // 耗时的数据处理
  return data.map(item => item * 2)
}

@Concurrent
function calculateFibonacci(n: number): number {
  if (n <= 1) return n
  return calculateFibonacci(n - 1) + calculateFibonacci(n - 2)
}

@Entry
@Component
struct TaskPoolDemo {
  @State result: string = ''
  @State isProcessing: boolean = false

  build() {
    Column({ space: 16 }) {
      Text('TaskPool任务池')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Button('执行单个任务')
        .width('100%')
        .onClick(() => {
          this.executeSingleTask()
        })

      Button('执行并发任务')
        .width('100%')
        .onClick(() => {
          this.executeConcurrentTasks()
        })

      Button('执行任务组')
        .width('100%')
        .onClick(() => {
          this.executeTaskGroup()
        })

      if (this.isProcessing) {
        LoadingProgress()
          .width(40)
          .height(40)
      }

      if (this.result) {
        Text(this.result)
          .fontSize(14)
          .fontColor('#666666')
          .padding(12)
          .backgroundColor('#f5f5f5')
          .borderRadius(8)
          .width('100%')
      }
    }
    .padding(16)
  }

  private async executeSingleTask() {
    try {
      this.isProcessing = true
      this.result = ''

      // 创建任务
      const task = new taskpool.Task(calculateFibonacci, 30)

      // 执行任务
      const result = await taskpool.execute(task) as number

      this.result = `斐波那契数列第30项: ${result}`
      console.log('任务执行完成:', result)
    } catch (error) {
      console.error('任务执行失败:', error)
      this.result = '任务执行失败'
    } finally {
      this.isProcessing = false
    }
  }

  private async executeConcurrentTasks() {
    try {
      this.isProcessing = true
      this.result = ''

      // 创建多个任务
      const tasks = [
        new taskpool.Task(calculateFibonacci, 25),
        new taskpool.Task(calculateFibonacci, 26),
        new taskpool.Task(calculateFibonacci, 27)
      ]

      // 并发执行所有任务
      const results = await Promise.all(
        tasks.map(task => taskpool.execute(task))
      )

      this.result = `并发结果: ${results.join(', ')}`
      console.log('并发任务完成:', results)
    } catch (error) {
      console.error('并发任务失败:', error)
      this.result = '并发任务失败'
    } finally {
      this.isProcessing = false
    }
  }

  private async executeTaskGroup() {
    try {
      this.isProcessing = true
      this.result = ''

      // 创建任务组
      const taskGroup = new taskpool.TaskGroup()
      
      // 添加任务到组
      taskGroup.addTask(new taskpool.Task(calculateFibonacci, 20))
      taskGroup.addTask(new taskpool.Task(calculateFibonacci, 21))
      taskGroup.addTask(new taskpool.Task(calculateFibonacci, 22))

      // 执行任务组
      const results = await taskpool.execute(taskGroup)

      this.result = `任务组结果: ${results.join(', ')}`
      console.log('任务组完成:', results)
    } catch (error) {
      console.error('任务组失败:', error)
      this.result = '任务组失败'
    } finally {
      this.isProcessing = false
    }
  }
}

3. Promise异步编程

typescript 复制代码
// 异步工具类
export class AsyncUtil {
  /**
   * 延时执行
   */
  static delay(ms: number): Promise<void> {
    return new Promise(resolve => {
      setTimeout(resolve, ms)
    })
  }

  /**
   * 带超时的Promise
   */
  static timeout<T>(
    promise: Promise<T>,
    timeoutMs: number
  ): Promise<T> {
    return Promise.race([
      promise,
      new Promise<T>((_, reject) => {
        setTimeout(() => {
          reject(new Error('操作超时'))
        }, timeoutMs)
      })
    ])
  }

  /**
   * 重试执行
   */
  static async retry<T>(
    fn: () => Promise<T>,
    maxRetries: number = 3,
    delayMs: number = 1000
  ): Promise<T> {
    let lastError: Error | undefined

    for (let i = 0; i < maxRetries; i++) {
      try {
        return await fn()
      } catch (error) {
        lastError = error as Error
        console.log(`第${i + 1}次尝试失败:`, lastError.message)

        if (i < maxRetries - 1) {
          await this.delay(delayMs)
        }
      }
    }

    throw lastError
  }

  /**
   * 批量并发执行(限制并发数)
   */
  static async parallelLimit<T, R>(
    items: T[],
    fn: (item: T) => Promise<R>,
    limit: number = 5
  ): Promise<R[]> {
    const results: R[] = []
    const executing: Promise<void>[] = []

    for (const item of items) {
      const promise = fn(item).then(result => {
        results.push(result)
      })

      executing.push(promise)

      if (executing.length >= limit) {
        await Promise.race(executing)
        executing.splice(executing.findIndex(p => p === promise), 1)
      }
    }

    await Promise.all(executing)
    return results
  }

  /**
   * 串行执行
   */
  static async serial<T, R>(
    items: T[],
    fn: (item: T) => Promise<R>
  ): Promise<R[]> {
    const results: R[] = []

    for (const item of items) {
      const result = await fn(item)
      results.push(result)
    }

    return results
  }
}

// 使用示例
@Entry
@Component
struct AsyncDemo {
  @State status: string = ''

  build() {
    Column({ space: 16 }) {
      Text('异步编程')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Button('带超时的请求')
        .width('100%')
        .onClick(() => {
          this.fetchWithTimeout()
        })

      Button('重试请求')
        .width('100%')
        .onClick(() => {
          this.retryRequest()
        })

      Button('限制并发数')
        .width('100%')
        .onClick(() => {
          this.limitedParallel()
        })

      if (this.status) {
        Text(this.status)
          .fontSize(14)
          .padding(12)
          .backgroundColor('#f5f5f5')
          .borderRadius(8)
          .width('100%')
      }
    }
    .padding(16)
  }

  private async fetchWithTimeout() {
    try {
      this.status = '请求中...'

      const result = await AsyncUtil.timeout(
        this.mockApiCall(),
        3000 // 3秒超时
      )

      this.status = `请求成功: ${result}`
    } catch (error) {
      this.status = `请求失败: ${error.message}`
    }
  }

  private async retryRequest() {
    try {
      this.status = '尝试请求...'

      const result = await AsyncUtil.retry(
        () => this.mockFailableApiCall(),
        3, // 最多重试3次
        1000 // 间隔1秒
      )

      this.status = `请求成功: ${result}`
    } catch (error) {
      this.status = `请求失败: ${error.message}`
    }
  }

  private async limitedParallel() {
    try {
      this.status = '批量处理中...'

      const items = Array.from({ length: 20 }, (_, i) => i)

      const results = await AsyncUtil.parallelLimit(
        items,
        async (item) => {
          await AsyncUtil.delay(1000)
          return item * 2
        },
        5 // 最多同时执行5个
      )

      this.status = `处理完成,结果数量: ${results.length}`
    } catch (error) {
      this.status = `处理失败: ${error.message}`
    }
  }

  private async mockApiCall(): Promise<string> {
    await AsyncUtil.delay(1000)
    return '数据加载成功'
  }

  private async mockFailableApiCall(): Promise<string> {
    await AsyncUtil.delay(500)
    
    // 70%概率失败
    if (Math.random() > 0.3) {
      throw new Error('网络错误')
    }

    return '请求成功'
  }
}

4. 多线程工具类

typescript 复制代码
// utils/ThreadUtil.ets
import worker from '@ohos.worker'
import taskpool from '@ohos.taskpool'

export class ThreadUtil {
  private static workerPool: Map<string, worker.ThreadWorker> = new Map()

  /**
   * 创建Worker
   */
  static createWorker(name: string, scriptPath: string): worker.ThreadWorker {
    if (this.workerPool.has(name)) {
      return this.workerPool.get(name)!
    }

    const workerInstance = new worker.ThreadWorker(scriptPath)
    this.workerPool.set(name, workerInstance)
    return workerInstance
  }

  /**
   * 销毁Worker
   */
  static destroyWorker(name: string): void {
    const workerInstance = this.workerPool.get(name)
    if (workerInstance) {
      workerInstance.terminate()
      this.workerPool.delete(name)
    }
  }

  /**
   * 销毁所有Worker
   */
  static destroyAllWorkers(): void {
    this.workerPool.forEach(worker => {
      worker.terminate()
    })
    this.workerPool.clear()
  }

  /**
   * Worker通信包装
   */
  static postToWorker<T>(
    workerName: string,
    message: any
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      const workerInstance = this.workerPool.get(workerName)
      if (!workerInstance) {
        reject(new Error('Worker不存在'))
        return
      }

      // 设置单次消息监听
      const messageHandler = (event: MessageEvent<T>) => {
        workerInstance.off('message', messageHandler)
        resolve(event.data)
      }

      const errorHandler = (error: ErrorEvent) => {
        workerInstance.off('error', errorHandler)
        reject(error)
      }

      workerInstance.on('message', messageHandler)
      workerInstance.on('error', errorHandler)
      workerInstance.postMessage(message)
    })
  }

  /**
   * TaskPool执行
   */
  static async executeTask<T>(
    fn: Function,
    ...args: any[]
  ): Promise<T> {
    const task = new taskpool.Task(fn, ...args)
    return await taskpool.execute(task) as T
  }

  /**
   * TaskPool批量执行
   */
  static async executeTasks<T>(
    tasks: Array<{ fn: Function, args: any[] }>
  ): Promise<T[]> {
    const taskList = tasks.map(({ fn, args }) => 
      new taskpool.Task(fn, ...args)
    )

    const results = await Promise.all(
      taskList.map(task => taskpool.execute(task))
    )

    return results as T[]
  }
}

关键要点

  1. Worker线程: 适合长时间运行的耗时任务
  2. TaskPool: 适合短时间的并发任务
  3. @Concurrent: 标记可并发执行的函数
  4. Promise: 异步编程的基础
  5. 避免阻塞: 耗时操作必须在子线程执行

最佳实践

  1. 合理选择: Worker用于持久任务,TaskPool用于短任务
  2. 资源管理: 及时销毁Worker,释放资源
  3. 错误处理: 捕获Worker和Task的错误
  4. 数据传递: 避免传递大对象,使用序列化数据
  5. 线程安全: 避免共享可变状态

参考资料

相关推荐
花开彼岸天~2 小时前
鸿蒙平台使用 `video_thumbnail` 插件指南
华为·harmonyos
特立独行的猫a2 小时前
QT开发鸿蒙PC应用:环境搭建及第一个HelloWorld
开发语言·qt·harmonyos·环境搭建·鸿蒙pc
花开彼岸天~2 小时前
Flutter跨平台开发鸿蒙化定位组件使用指南
flutter·华为·harmonyos
sinat_384241094 小时前
HarmonyOS音乐播放器开发实战:从零到一打造完整鸿蒙系统音乐播放器应用 1
华为·harmonyos
个案命题5 小时前
鸿蒙ArkUI状态管理新宠:@Once装饰器全方位解析与实战
华为·harmonyos
云_杰6 小时前
取件伙伴性能提升——长列表
性能优化·harmonyos
花开彼岸天~7 小时前
Flutter跨平台开发鸿蒙化日志测试组件使用指南
flutter·elasticsearch·harmonyos
妮妮分享7 小时前
Harmony NEXT 定位 SDK:开启鸿蒙原生应用精准定位新时代
华为·harmonyos
w139548564228 小时前
在鸿蒙平台使用 sqlite3.dart 插件
华为·sqlite·harmonyos