当前位置: 首页 > news >正文

FFRT的核心并发范式与样例概览

在深入了解代码前,我们先通过一个表格来梳理FFRT支持的三种核心并发范式及其适用场景,这有助于你根据实际需求选择合适的模型。

并发范式核心特点适用场景
图依赖并发通过任务依赖关系构建有向无环图(DAG),运行时自动调度任务间存在明确的先后顺序或复杂的依赖关系
串行队列任务按提交顺序依次执行,保证执行顺序需要避免资源竞争、确保任务顺序执行的场景
并发队列多个任务同时执行,充分利用多核资源任务间相互独立,需要提升并发性能的场景

样例一:图依赖并发——流媒体视频处理

这是一个非常经典的任务依赖案例,模拟视频上传后的处理流程:解析 → (转码 & 生成缩略图) → 添加水印 → 发布。其中转码和生成缩略图可以并行执行。

c

#include <stdio.h>
#include "ffrt/ffrt.h"// 定义各个处理任务函数
void func_TaskA(void* arg) { printf("视频解析\n"); }
void func_TaskB(void* arg) { printf("视频转码\n"); }
void func_TaskC(void* arg) { printf("视频生成缩略图\n"); }
void func_TaskD(void* arg) { printf("视频添加水印\n"); }
void func_TaskE(void* arg) { printf("视频发布\n"); }int main()
{// 提交任务A(视频解析),它没有前置依赖ffrt_task_handle_t hTaskA = ffrt_submit_h_f(func_TaskA, NULL, NULL, NULL, NULL, ffrt_auto_destroy_no);// 提交任务B(视频转码)和任务C(生成缩略图),它们都依赖于任务Affrt_dependence_t taskA_deps[] = {{ffrt_dependence_task, hTaskA}};ffrt_deps_t dTaskA = {1, taskA_deps};ffrt_task_handle_t hTaskB = ffrt_submit_h_f(func_TaskB, NULL, &dTaskA, NULL, NULL, ffrt_auto_destroy_no);ffrt_task_handle_t hTaskC = ffrt_submit_h_f(func_TaskC, NULL, &dTaskA, NULL, NULL, ffrt_auto_destroy_no);// 提交任务D(添加水印),它依赖于任务B和任务C的完成ffrt_dependence_t taskBC_deps[] = {{ffrt_dependence_task, hTaskB}, {ffrt_dependence_task, hTaskC}};ffrt_deps_t dTaskBC = {2, taskBC_deps};ffrt_task_handle_t hTaskD = ffrt_submit_h_f(func_TaskD, NULL, &dTaskBC, NULL, NULL, ffrt_auto_destroy_no);// 提交任务E(视频发布),它依赖于任务D的完成ffrt_dependence_t taskD_deps[] = {{ffrt_dependence_task, hTaskD}};ffrt_deps_t dTaskD = {1, taskD_deps};ffrt_submit_f(func_TaskE, NULL, &dTaskD, NULL, NULL);// 等待所有任务执行完毕ffrt_wait();// 手动销毁任务句柄ffrt_task_handle_destroy(hTaskA);ffrt_task_handle_destroy(hTaskB);ffrt_task_handle_destroy(hTaskC);ffrt_task_handle_destroy(hTaskD);return 0;
}

代码解读

  1. 依赖构建:使用 ffrt_dependence_t 和 ffrt_deps_t 结构体来显式定义任务间的依赖关系。例如,任务B和C的依赖列表 dTaskA 中包含了任务A的句柄,这意味着它们必须等A执行完后才开始。

  2. 并行性:由于任务B和C都只依赖A,且彼此没有依赖,FFRT运行时可以自动让它们并行执行,从而高效利用多核CPU。

  3. 同步等待ffrt_wait() 会阻塞主线程,直到整个任务图中的所有任务都执行完成,确保流程的完整性。

样例二:数据依赖——斐波那契数列计算

这个例子展示了如何用数据依赖而非任务句柄来表达任务间的关系,非常适合计算有向无环图结构的数值,比如斐波那契数列 F(n) = F(n-1) + F(n-2)

c

#include <stdio.h>
#include "ffrt/ffrt.h"typedef struct {int input;int* output;
} fib_data_t;void fib_task(void* arg) {fib_data_t* data = (fib_data_t*)arg;int n = data->input;int* result = data->output;if (n <= 1) {*result = n; // 递归基} else {int result1, result2;fib_data_t data1 = {n - 1, &result1};fib_data_t data2 = {n - 2, &result2};// 定义数据依赖:当前任务消耗input数据,产出output数据ffrt_dependence_t in_deps[] = {{ffrt_dependence_data, &data->input, ffrt_dep_type_in}};ffrt_dependence_t out_deps[] = {{ffrt_dependence_data, data->output, ffrt_dep_type_out}};ffrt_deps_t deps_in = {1, in_deps};ffrt_deps_t deps_out = {1, out_deps};// 提交子任务,计算F(n-1)和F(n-2)ffrt_submit_f(fib_task, &data1, &deps_in, &deps_out, NULL, ffrt_task_attr_default);ffrt_submit_f(fib_task, &data2, &deps_in, &deps_out, NULL, ffrt_task_attr_default);// 等待两个子任务完成并汇总结果ffrt_wait();*result = result1 + result2;}
}int main() {int n = 10;int final_result;fib_data_t main_data = {n, &final_result};// 计算F(10)ffrt_submit_f(fib_task, &main_data, NULL, NULL, NULL, ffrt_task_attr_default);ffrt_wait(); // 等待整个计算过程完成printf("F(%d) = %d\n", n, final_result);return 0;
}

代码解读

  1. 数据签名:依赖关系不再通过任务句柄,而是通过数据的地址(如 &data->input)来标识。FFRT会跟踪这些数据的生产者和消费者。

  2. 依赖类型

    • ffrt_dep_type_in:表示本任务需要读取该数据。

    • ffrt_dep_type_out:表示本任务会修改或生产该数据。

  3. 自动同步:运行时根据数据依赖自动确保:当计算 F(n) 时,其依赖的 F(n-1) 和 F(n-2) 必定已经计算完成。这完美体现了 Producer-Consumer 依赖关系。

样例三:串行队列——顺序访问共享资源

当多个任务需要按顺序访问某个共享资源(如一个配置文件、一段内存或一个硬件设备)时,串行队列是最简单可靠的选择。

c

#include <stdio.h>
#include "ffrt/ffrt.h"// 模拟一个共享资源
int shared_counter = 0;void task_increment(void* arg) {// 此任务在串行队列中执行,无需加锁shared_counter++;printf("Task Increment: shared_counter is now %d\n", shared_counter);
}void task_double(void* arg) {shared_counter *= 2;printf("Task Double: shared_counter is now %d\n", shared_counter);
}int main() {// 创建一个串行队列属性ffrt_queue_attr_t attr;ffrt_queue_attr_init(&attr);ffrt_queue_attr_set_type(attr, ffrt_queue_serial);// 将任务提交到同一个串行队列中for (int i = 0; i < 5; i++) {// 任务将按for循环的提交顺序依次执行ffrt_submit_f(task_increment, NULL, NULL, NULL, &attr, ffrt_task_attr_default);ffrt_submit_f(task_double, NULL, NULL, NULL, &attr, ffrt_task_attr_default);}ffrt_wait();printf("Final value: %d\n", shared_counter);ffrt_queue_attr_destroy(attr);return 0;
}

代码解读

  1. 顺序保证:通过 ffrt_queue_attr_set_type(attr, ffrt_queue_serial) 设置串行队列,所有提交到此队列的任务都会严格按照先进先出(FIFO) 的顺序执行。

  2. 数据安全:因为同一时间只有一个任务在执行,所以对 shared_counter 的修改是绝对安全的,无需使用锁,简化了编程模型,避免了死锁风险。

开发注意事项

  1. 任务粒度:FFRT适合调度任务粒度不小于100微秒的计算任务。任务过小,调度开销占比会变大;任务过大,则无法充分利用系统并行度。

  2. 依赖管理:务必正确设置任务依赖,否则可能导致数据竞争或任务无法执行。对于不再使用的任务句柄,记得使用 ffrt_task_handle_destroy 进行销毁。

  3. 等待与同步ffrt_wait() 是一个强大的同步原语,它会等待调用者提交的所有任务(包括子孙任务)都完成。在需要协调多个任务结果的场景下非常有用。

希望以上样例能帮助你直观地理解并上手鸿蒙NEXT的FFRT开发。在实际项目中,灵活运用这些并发范式,可以极大地提升应用程序的性能和响应能力。

http://www.dtcms.com/a/483429.html

相关文章:

  • 用jsp做一网站的流程佛山app开发公司排名
  • 建立网站需要怎么做从网络安全角度考量_写出建设一个大型电影网站规划方案
  • CRMEB多商户系统(Java) v2.0公测版发布
  • 网站后台发文章图片链接怎么做泰州市建设监理协会网站
  • SQL性能调优:深入理解数据库索引的原理与应用
  • sqlite:存储时间
  • 跳过 OA 拿 TikTok DE offer!三轮面经 + 真题通俗解析
  • 想做一个自己的网站程序开发平台哪个好
  • 兰州彩票网站制作在线设计平台的技术支持
  • 【GESP】C++四级真题 luogu-B3958 [GESP202403 四级] 相似字符串
  • Kubernetes 集群调度
  • 【Linux 系统】互斥与同步
  • 网站 301做电脑游戏破解的网站
  • 软件培训网站个人不良信息举报网站
  • 深圳品牌网站策划网站流量一直下降
  • Qiankun 主子应用通信方式对比及使用场景【前端微前端实战指南】
  • 二级域名网站优化肥城网站建设费用
  • 网站模板下载后怎么使用网络规划设计师 高级
  • python高效采集淘宝商品数据,详情页实时 API 接口接入
  • 个人房产信息查询网站企业查查官网登录入口
  • 沈阳制作网站的公司四平做网站佳业
  • Thinkphp8 Redis队列与消息队列topthink/think-queue 原创
  • LeetCode每日一题——螺旋矩阵
  • lamp网站开发实战工程机械网官网
  • .net AI MCP 入门 适用于模型上下文协议的 C# SDK 简介(MCP)
  • 做网站哪里需要用钱dedecms做电影网站
  • ZYNQ裸机开发指南笔记
  • Starlake:一款免费开源的ETL数据管道工具
  • 线性代数 | 要义 / 本质 (上篇)
  • 求网站建设和网页设计的电子书自己怎么给网站做优化