鸿蒙并发能力TaskPool与内存共享并发模型对比

鸿蒙多线程并发

鸿蒙开发提供两种并发能力:TaskPool和Worker
两种能力都是基于Actor模型实现,是典型的内存不共享并发模型,每个线程都会创建独立的Actor,管理各自的独立内存,彼此之间通过通信机制实现数据交流

以经典的消费生产问题为例

内存共享模型下通过信号量PV操作模拟:

  • 生产者生成数据后,放在一个缓冲区
  • 消费者从缓冲区取出数据
  • 任何时刻只允许一个消费者或生产者访问缓冲区

说明

  • 操作缓冲区需要互斥
  • 缓冲区空时,消费者需要等待生产者生产,需要同步

需要三个信号量

  • 互斥信号量murex:用于访问缓冲区,初始化为1;
  • 资源信号量fullBuffers:用于消费者询问缓冲区是否有数据,有数据则读取,初始化为0(缓冲区一开始为空)
  • 资源信号量emptyBuffers:用于生产者询问缓冲区是否有空位,有空位则生成数据,初始化为n(缓冲区大小)
void Producer(){
    while(TRUE){
        P(emptyBuffers);//将空槽数量-1
        P(mutex);//进入临界区
        将生成的数据放入缓冲区;
        V(mutex);//离开临界区
        V(fullBuffers);//将内容物个数+1
    }
}

void consumer(){
    while(TRUE){
        P(fullBuffers);//内容物个数-1
        P(mutex);
        从缓冲区读取数据;
        V(mutex);
        V(emptyBuffers);//空槽数量+1
    }
}

内存不共享的基于Actor模型的TaskPool并发能力模拟:

import { taskpool } from '@kit.ArkTS';
// 跨线程并发任务
@Concurrent
async function produce(): Promise<number>{
  // 添加生产相关逻辑
  console.log("producing...");
  return Math.random();
}

class Consumer {
  public consume(value : Object) {
    // 添加消费相关逻辑
    console.log("consuming value: " + value);
  }
}

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        Button() {
          Text("start")
        }.onClick(() => {
        //此处为并发逻辑
          let produceTask: taskpool.Task = new taskpool.Task(produce);
          let consumer: Consumer = new Consumer();
          for (let index: number = 0; index < 10; index++) {
            // 执行生产异步并发任务
            taskpool.execute(produceTask).then((res : Object) => {
              consumer.consume(res);
            }).catch((e : Error) => {
              console.error(e.message);
            })
          }
        })
        .width('20%')
        .height('20%')
      }
      .width('100%')
    }
    .height('100%')
  }
}

可以看到,TaskPool能力相较于传统共享内存下并发开发的优势在于各线程内存独立,因此不需要对共享资源区的操作加锁,TaskPool线程之间通过序列化信息通讯,生产者线程将信息序列化发送给UI线程,UI线程消费结果后将生产任务发送给生产者,对线程的调度在TaskPool内部实现了封装
在这里插入图片描述

TaskPool支持开发者在主线程封装任务抛给任务队列,系统选择合适的工作线程,进行任务的分发及执行,再将结果返回给主线程。

### 鸿蒙系统多线程并发编程实现方式 鸿蒙系统的多线程并发编程主要依赖于 `TaskPool` `Worker` 两种机制来实现[^1]。这两种机制分别适用于不同的场景: #### TaskPool 的特点 `TaskPool` 是一种面向任务的并发模型,适合用于短耗时、轻量级的任务调度。它允许开发者提交独立的任务到线程池中执行,而无需关心底层线程的生命周期管理。这种设计使得开发者可以专注于业务逻辑本身,而不是复杂的线程管理同步问题[^4]。 以下是使用 `TaskPool` 提交任务的一个简单示例: ```typescript import taskpool from '@ohos.taskpool'; const myTask = () => { console.log('This is a lightweight task.'); }; taskpool.schedule(myTask); ``` #### Worker 的特点 相比之下,`Worker` 更倾向于线程级别的控制,适合处理长耗时或者高计算密集型的任务。通过 `Worker`,开发者可以直接创建一个新的线程,并显式地管理其生命周期,包括初始化、销毁以及错误处理等环节[^5]。 下面是一个典型的 `Worker` 使用案例: ```typescript // 创建 Worker 实例 let workerInstance = new Worker('path/to/workerScript.ts'); // 接收来自 Worker 的消息 workerInstance.onmessage = (event: MessageEvent) => { console.log('Received result:', event.data); }; // 向 Worker 发送数据 workerInstance.postMessage({ key: 'value' }); // 销毁 Worker 实例 workerInstance.terminate(); ``` #### 并发模型的选择 在实际开发过程中,选择合适的并发模型至关重要。鸿蒙系统支持基于内存共享基于消息通信两类并发模型。其中,`Actor` 并发模型作为一种基于消息通信的方式,在避免锁竞争方面表现优异,能够显著提升程序的稳定性性能[^2]。 对于需要频繁跨线程传递数据的应用场景,推荐采用序列化策略优化通信效率,比如利用 `ArrayBuffer` 替代复杂对象结构减少拷贝成本;同时也可以考虑批量传输方案进一步降低通信频率带来的开销[^5]。 另外需要注意的是,在涉及共享资源的情况下,可以通过 `Atomics API` 来保障操作的安全性,防止因竞态条件引发的数据不一致问题。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值