首页/文章/ 详情

博客|介绍 Qt 6.11 版本更新中的 Qt Task Tree 模块

5月前浏览1124

全新的Qt Task Tree模块即将作为技术预览版随Qt 6.11版本发布,是一个管理自动化异步任务的全面解决方案。


它最特别的一点是,在Qt C++ API设计上采用了全新的方法,改变了我们编写和读取异步代码 (asynchronous code)的思维方式。此外,它还统一了各种异步API(asynchronous APIs),提供了让任 意异步任务(asynchronous task)适配本模块的方法。


Qt Task Tree 演示示例截图


全新的声明式 Qt C++ API 方案 


Qt以其用QML语言表达的声明式API而闻名。新的Qt Task Tree模块将这种声明式API的理念带到了Qt的C++世界 。


声明式配方 (recipe) 和Task Tree

异步工作流(asynchronous workflow)的声明式描述是通过所谓的配方(recipe)来表达的。配方(recipe)是一个可复 制的值类型对象,会被传递给Task Tree实例。当Task Tree启动时,它会读取recipe,并根据传递的配方自动管理复杂的异步工作流。工作流包括动态创建异步任务、创建用于任务间数据交换的数据对象、已创建任务的生命周期管理以及在任务完成后执行后续操作。

Recipe是可重复使用的——这意味着它们可以作为通用配方的一部分,可以多次运行,或由多个并行运行的Task Tree来运行。


卡带和播放器的类比

可以将配方(recipe)和Task Tree比作卡带和卡带播放器。卡带本身不会执行任何操作。同样,在定义配方时,您不会创建任何任务或数据对象。当配方传递给Task Tree并启动Task Tree时,您只是定义了Task Tree应该做的具体描述。这正如将卡带插入播放器并开始播放时发生的情形——播放器读取卡带内容后,便能精确执行相应操作。 

当您想创建一个新游戏时,您只需设计一个新的游戏卡带,然后让玩家根据卡带的内容来执行它。卡带设计者不需要改变播放器中的任何内容,只需在插入卡带后按下“播放“/”取消“/”重置“按钮即可。配方(recipes)也是一样:若想编写自己的复杂异步工作流,只需准备专属配方。随后将其传入Task Tree,即可对Task Tree进行播放/取消/重置操作。无需对Task Tree本身做任何修改就能正确执行配方。

这种代码编写思维的转变,是成功使用此模块的关键因素。 


职责划分

作为Qt首个声明式C++ API,了解如何使用它以及区分配方(recipe)和 Task Tree 的确切职责至关重要。

Qt Task Tree模块的用户重点是创建一个精确描述所需异步工作流程的配方。 配方的内容完全是声明性的,重要的是要记住它只是一个描述,仅此而已。

另一件需要记住的重要事情是,Task Tree本身就是一个配方阅读器/执行器。使用Task Tree很简单--您不需要(也不应该)创建QTaskTree子类,只需将配方传递给它并运行即可。然后,您可以取消/重置它,或接收完成通知,仅此而已。

这就是Task Tree为您带来的最大好处--在Task Tree的引擎盖下,Task Tree 为您完成了大量枯燥的重复工作,而无需额外编码。

让我们来看看配方和Task Tree的具体职责,以及配方内容如何影响正在运行的Task Tree:


配方(卡带),由用户定义并描述:    
QTaskTree(播放器),由用户实例化,读取传递的配方并自动执行以下操作:    
需要执行哪些任务    
创建和销毁任务,负责管理其生命周期    
执行顺序    
遵守配方定义的任务执行顺序    
执行模式(顺序、并行)    
按顺序或并行执行任务    
工作流程策略    
根据已完成任务的结果和已定义的工作流程策略,通过继续执行、跳过剩余任务和取消并行运行的任务来控制执行    
嵌套组    
执行一组子任务,其父任务将其视为单个异步任务,拥有自己的执行模式和工作流策略    
设置处理程序    
在任务或组启动前执行设置处理程序,以便根据用户需求配置任务    
完成处理程序    
在任务或组结束时执行完成处理程序,以便从已完成的任务中收集结果数据    
用于任务间数据交换的Storage<DataType> 对象    
动态创建和销毁由相应 Storage<DataType>  对象描述的 DataType 对象,用于不同任务和组的设置和完成处理程序或条件表达式中    
条件表达式    
根据收集的数据或异步任务结果选择不同的执行路径    


此外,QTaskTree还提供有关已完成任务的基本进度信息,并能取消所有当前正在运行的任务,不论当前的执行状态如何。从开发人员的角度来看,唯一的工作就是定义配方(表格左列)。在表格的右栏,您可以看到QTaskTree为您完成多少工作,无需要任何额外代码。这几乎消除了异步编程中通常需要的所有冗余代码。


声明式方法的力量

从模板代码中明确分离出确切的工作流程,使代码比传统方法更具可读性Task Tree为您处理了繁琐的任务,模板代码便不复存在。 另一方面,即使工作流程再复杂,也能在单一位置清晰、准确地描述出来。


让我们来看一个简单的示例配方。


 


配方由顶层的Group元素组成。在这个元素中,我们定义了属性和任务。请注意下面的解释中使用了  "when this recipe is run" (当此配方运行时)这一短语,强调事情不是在定义配方时发生的,而是在配方执行期间发生的。


第一个属性值是sequential,这意味着当运行此配方时,顶层组的直接子任务将以链式方式执行,即前一个任务完成后,下一个任务才开始执行。顺序元素是任何组的默认执行模式,可以省略。


第二个属性值是stopOnError。这意味着在运行此配方时,只要顶层组的任何直接子任务出错退出,我们就会停止执行此组,跳过所有待定任务,并报告错误。否则,在所有任务都成功完成后,我们就会报告执行成功。这也是任何组的默认工作流策略,因此也可以省略。


接下来,我们定义顶层Group的第一个任务QNetworkReplyWrapperTask,该任务将在运行此配方时异步检索网络数据。


顶层组的最后一个元素是嵌套Group。 运行此配方时,它将在下载任务成功完成后执行。该组包含Parallel属性,确保所有任务并行执行。最后,我们定义了两个QConcurrentCallTask任务,每个任务都会在运行此配方时执行一个在单独线程中运行的函数,将收集到的网络数据转换为所需大小的QImage。


最后一步是将配方传递给QTaskTree实例并运行它。


统一多样的异步 API


Qt Task Tree模块解决了异步编程的一个重要方面,将各种异步API统一为一个的接口。


如果没有这种统一,要自动创建、启动、通知任务完成和删除不同类型的任务将非常困难。 下表显示了不同的异步Qt API如何启动任务。创建、完成和销毁API也存在类似的差异。


异步任务    
启动 API    
进程    
QProcess::start()    
网络查询    
QNetworkAccessManager::get()/put()/post()/other…
Instantiates QNetworkReply dynamically.    
在独立线程中运行    
QtConcurrent::run()
Returns QFuture handle    
定时器    
QTimer::singleShot()    


在Qt Task Tree模块中,异步API的不兼容性问题已得到解决。所有这类任务类型都通过统一接口实现了标准化,该接口利用为现有API提供的任务适配器实现。有关内置适配器以及如何适配任何其他自定义异步任务类型的更多信息,请参阅QTaskInterface和QCustomTask文档。


运行中的Task Tree


Qt Task Tree模块最初是在2022年底作为QtCreator项目的一部分开发的。在此期间,我们增加了许多改进,仅举几例:


  • 在 For 循环中运行部分配方
  • 在异步任务中直接使用条件表达式:If () >> Then {} >> Else {}
  • 用于异步任务的逻辑运算符,如连接、析取和否定,以短路方式运行
  • 便捷的 Task Tree 运行程序,可实现单个/顺序/并行/映射执行配方

Qt Task Tree最终发展成熟,在Qt 6.11中作为公共API发布。目前,QtCreator中已有超过100处功能采用Qt Task Tree进行管理,包括管理构建/部署/运行项目配置、控制所有定位器过滤器的执行、执行VCS命令、驱动Axivion插件网络通信、执行Clang工具、运行自动测试,等等.……


Qt Task Tree模块包含几个演示其功能的示例。让我们简单了解一下:


执行模式和工作流策略实验

演示示例展示了不同的执行模式和工作流策略如何影响复杂Task Tree结构中子任务的执行。它还允许您观察任务持续时间及其预期结果如何影响执行的持续性。该示例也有网络组件版本,因此您可以直接在浏览器中使用。  


   状态机的可能性   

Traffic Light示例演示了如何将Task Tree用作状态机。它展示了如何使用Forever元素来构建可作为状态机运行的重复配方。


并行运行迭代

使用Qt Task Tree,可以同时启动所有异步迭代。图像缩放示例展示了这一点。它还解释了如何使用存储对象(Storage object)在不同任务之间交换动态数据。


 

来源:IFD优飞迪

二次开发通用电子通信云计算游戏数字孪生控制Creator
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2026-03-13
最近编辑:5月前
优飞迪科技
赋能新仿真,创优新设计
获赞 323粉丝 349文章 519课程 4
点赞
收藏
作者推荐
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈