首页 > 其他分享 >使用QFuture和QFutureWatcher实现不阻塞界面的Async函数

使用QFuture和QFutureWatcher实现不阻塞界面的Async函数

时间:2025-01-16 20:33:12浏览次数:1  
标签:include QFutureWatcher args watcher QtConcurrent future Async QFuture

简述

很多时候,在Qt里面需要运行一个耗时函数的时候,为了避免阻塞界面,需要放入非主线程去执行。
实现这样处理的方法有好几种,例如:

  • 写一个继承自QThread类,实现run接口;
  • 写一个继承自QObject的类,添加槽函数执行任务,创建对象,移入一个QThread中进行调用;
  • 写一个QRunnable的子类,创建对象,添加到QThreadPool里面去调用;

上面的方法都比较麻烦些,可以使用QtConcurrent来进行简化。

这里采用基于QtConcurrent的实现,来简化这种异步调用过程,使用QEventLoop来等待执行结束,模拟同步调用。

代码

#include <QDebug>
#include <QEventLoop>
#include <QFutureWatcher>
#include <QtConcurrent/QtConcurrentRun>
#include <functional>
#include <iostream>


template<typename Func, typename... Args>
auto WaitRunAsync(Func&& func, Args&&... args) -> decltype(func(args...))
{
    using ReturnType = decltype(func(args...));

    // 将函数和参数绑定为一个可调用对象
    auto task = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);

    // 使用 QtConcurrent::run 异步执行任务
    QFuture<ReturnType> future = QtConcurrent::run(task);

    // 创建 QFutureWatcher 来监视任务状态
    QFutureWatcher<ReturnType> watcher;

    if (qApp != nullptr) {
        QEventLoop loop;
        // 连接信号槽
        QObject::connect(&watcher, &QFutureWatcher<ReturnType>::finished, &loop, &QEventLoop::quit);
        // 设置 QFutureWatcher 的 future
        watcher.setFuture(future);
        // 使用 QEventLoop 等待任务完成
        loop.exec();
    }
    else {
        // 设置 QFutureWatcher 的 future
        watcher.setFuture(future);
        // 等待计算完成
        watcher.waitForFinished();
    }
    std::cout << "event loop quit!" << std::endl;
    // 返回任务结果
    return future.result();
}

// 示例任务函数
int exampleTask(int a, int b)
{
    std::cout << "Task is running with arguments: " << a << ", " << b << std::endl;
    QThread::sleep(2);   // 模拟耗时操作
    std::cout << "Task completed!" << std::endl;
    return a + b;
}

int main()
{
    std::cout << "Main thread ID: " << QThread::currentThreadId() << std::endl;

    for (int i = 0; i < 3; ++i) {
        std::cout << "run task " << i << std::endl;
        // 异步执行任务并等待完成,获取返回值
        int result = WaitRunAsync(exampleTask, 10, 20);
        std::cout << "Task result: " << result << std::endl;
    }
    std::cout << "Back to main thread!" << std::endl;
    return 0;
}

标签:include,QFutureWatcher,args,watcher,QtConcurrent,future,Async,QFuture
From: https://www.cnblogs.com/oloroso/p/18675718

相关文章

  • rust学习十七.1、async和await
    本文对应相关书籍17.1章节。先言:async和多线程没有什么密切关系,当然也不是毫无关系!一、async在rust到底是什么async中文的意思是异步,在编程中指的是:执行一段代码,主线程可以在等待完成之前,先做其它事情。如果有写过前端代码,就明白这个东西。例如经典的jquery的ajax默认就是异步......
  • @await Html.PartialAsync
    @awaitHtml.PartialAsync是ASP.NETCoreMVC中的一个Razor视图语法,用于异步加载一个视图片段(PartialView)。作用视图复用:可以将一些通用的UI组件或内容封装成视图片段,然后在不同的页面或视图中通过 @awaitHtml.PartialAsync 来引入,避免代码重复,提高开发效率和代码的......
  • 【转】[C#] WebAPI 使用async和await
    转自:kimi.ai在.NETFramework4.5及以上版本中,WebAPI支持async和await关键字的使用。使用async和await对调用方(客户端)和服务器端都有不同的影响,以下是详细说明:对调用方(客户端)的影响响应时间:对于单个客户端请求来说,使用async并不会显著减少请求的响应时间。无论是同步还是......
  • 请说说`<script>`、`<script async>`和`<script defer>`的区别
    在前端开发中,<script>标签用于嵌入或引用JavaScript代码。<script>标签有几个属性可以影响脚本的加载和执行方式,其中async和defer是两个常用的属性。以下是它们之间的主要区别:普通的<script>:当浏览器遇到<script>标签时,它会立即下载并执行该脚本。在执行脚本期......
  • nuxt3 useFetch useAsyncData $fetch 区别
    1.useFetchuseFetch是一个用于获取数据的高层次工具,结合了useAsyncData和$fetch的功能,特别适用于需要与Nuxt3的服务器端渲染(SSR)集成的情况。特点:自动处理状态:useFetch会自动处理加载状态、错误状态以及数据缓存。SSR支持:它默认支持SSR,并会在服务器端预取数据。返......
  • 前端必知:async/await与Promise深度剖析
    文章目录一、引言二、Promise基础入门2.1Promise是什么2.2三种状态详解2.3基本用法示例三、async/await初相识3.1语法糖的魅力3.2基本使用规则3.3代码示例展示四、两者的关联与区别4.1关联:async/await与Promise协同4.2区别:语法、错误处理与适用场景五、......
  • `QualitySettings.asyncUploadPersistentBuffer
    在Unity中,`QualitySettings.asyncUploadPersistentBuffer`是一个静态属性,它控制着纹理上传到GPU的异步方式。当启用时(设置为`true`),Unity会创建一个持久的缓冲区用于异步上传纹理数据到GPU,这可以提高性能,尤其是在有大量纹理需要加载或更新的情况下。具体来说,当使用异步纹......
  • Hyperf async-queue 队列 [ERROR] RedisException: read error on connection to xxx
    起因:在redis异步队列中总是有很多超时的任务,于是将redis-queue的任务超时时间调整到了3600async_queue.php'default'=>['driver'=>\Hyperf\AsyncQueue\Driver\RedisDriver::class,'redis'=>['pool'=>'def......
  • C# async void 方法中使用await不会异步等待
    asyncvoid通常用于事件处理程序或其他不需要返回值的情况,好像是一个为了解决历史遗留问题创建的机制,非必要情况下,不建议使用asyncvoid,推荐使用asyncTask替代asyncvoid和主线程貌似是一个线程,如果asyncvoid中存在异步等待时,执行到await时,会在等待的同时切换到其他线程(主线......
  • async 与 await
    async和await是用于编写异步代码的关键字,允许程序在执行I/O操作(如网络请求、文件读写等)时不阻塞其他代码的执行。这样可以提高程序的并发性能,使其在处理多个任务时更加高效。async用于定义一个异步函数(协程),而await用于暂停协程的执行,等待某个耗时操作完成。通过这种方式,......