Qt 之 Concurrent 4、【例】并发函数Run用法示例

QtConcurrent::run

QtConcurrent::run() 函数在单独的线程中运行一个函数,也就是说这是一种便捷的使用多线程的方法,实现异步运算。

使用QtConcurrent::run() 执行步骤如下:

  • 添加模块 QT += concurrent
  • 添加头文件 #include <QtConcurrent>
  • 调用 QtConcurrent::run() 函数

1、QtConcurrent::run() 原型

QtConcurrent::run()的原型很多,但是最基本的是以下 4 种,返回类型是QFuture,返回的结果在QFuture里面。

  • QFuture< T > run( Function function ),无参
  • QFuture< T > run( Function function, const Arg1 &arg1 ⋯ \cdots const Arg5 &arg5),有参,参数最多5个
  • QFuture< T > run( const Class *object, Function function ⋯ \cdots ) 成员函数
  • QFuture< T > run(QThreadPool *pool, const Class *object, Function function ⋯ \cdots ) 指定 QThreadPool 的成员函数

Function 是一个函数类型,由函数返回值和参数类型、个数决定。

2、同步和异步的效果对比

异步运行,主要是为了防止一些耗时的运算会阻塞当前线程,QtConcurrent::run 的出现使得异步执行变得轻快🏃

  • 有一个耗时的计算过程 getCount()

    void getCount(){		// 无参无返回值
      int i = 0;
      while (i < 3) {
        qDebug() << i;
        Sleep(1000); // 1000 ms
        ++i;
      }
      return;
    }
    
  • 同步运行会阻塞当前线程

    #include <QApplication>
    #include <QDebug>
    #include <windows.h>
    
    void getCount();
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      qDebug() << "start";
      getCount ();  // 耗时工作
      qDebug() << "end";
      return 0;
    }
    

    结果如下:当前的主线程被阻塞,等待getCout函数执行完毕,才结束

    image-20210610111459756

  • 使用QtConcurrent::run() 异步执行

    • 添加模块 QT += concurrent
    • 添加头文件 #include <QtConcurrent>
    • 在main 里 调用 QtConcurrent::run()
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      qDebug() << "start";
      QtConcurrent::run( getCount );
      qDebug() << "end";
      return 0;
    }
    

    运行结果,如下图:

image-20210610112339741

可见在异步执行中,主线程从头到尾运行完毕,完全没有被耗时的工作阻塞。

3、传递参数

只要知道了 QtConcurrent::run() 原型,就可以很简单地调用,参数最多5个,如果多余5个,可用容器定义函数。

void getCount(int n){		// 有参无返回值
  int i = 0;
  while (i < n) {
    qDebug() << i;
    Sleep(1000); // 1000 ms
    ++i;
  }
  return;
}

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  qDebug() << "start";
  QtConcurrent::run( getCount, 4 );
  qDebug() << "end";
  return 0;
}
// 截图略

4、获取返回值

QtConcurrent::run() 的返回值存在 QFuture 中,需要调用 QFuture 的成员函数来获取 。

谨记:QFuture 的结果查询函数,都是阻塞型的,他们都会等待 QtConcurrent::run() 结束。

QFuture 结果查询的函数
T result() constresultAt(0),阻塞型
T resultAt(int index) const阻塞型
resultCount() const结果数量,如果不阻塞,返回值不准确
QList< T > results() const结果集合,阻塞型

修改上面的代码,如下:

int getCount(int n){			// 有参有返回
  int i = 0;
  while (i < n) {
    qDebug() << i;
    Sleep(1000); // 300ms
    ++i;
  }
  return n;
}

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  qDebug() << "start";
  QFuture<int> f = QtConcurrent::run( getCount, 4 );
  qDebug()<< f.result ()  << f.resultCount () ;  // 会阻塞线程
  qDebug() << "end";
  return 0;
}

这么些,异步执行有啥意义呢?

5、使用QFutureWatcher的信号槽

QFuture 类本身未继承QObject,所以没法直接使用信号槽,所以需要另外一个监视类 QFutureWatcher。

使用步骤:

  1. 定义QFutureWatcher
    QFutureWatcher<int> watcher;
  2. 设置监视对象 QFuture
    watcher.setFuture(future);
  3. 使用QFutureWatcher信号槽
    connect(&watcher, &QFutureWatcher<int>::finished ... );

代码如下:

#include <QApplication>
#include <QDebug>
#include <windows.h>
#include <QtConcurrent>
#include <QFutureWatcher>

int getCount(int n){			// 有参有返回
  qDebug() << "start" << QThread::currentThread ();
  int i = 0;
  while (i < n) {
    qDebug() << i;
    Sleep(1000); 
    ++i;
  }
  qDebug() << "end" << QThread::currentThread ();
  return n;
}

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  qDebug() << "start" << QThread::currentThread ();
  QFuture<int> f = QtConcurrent::run( getCount, 4 );

  QFutureWatcher<int> w;
  w.setFuture (f);
  QObject::connect (&w,&QFutureWatcher<int>::finished,[&]{
    qDebug() << QThread::currentThread ();
    qDebug()<< f.result ()  << f.resultCount () ;
    a.quit ();    // 主动退出,否则进程一直在循环
  });
  qDebug() << "end" << QThread::currentThread ();
  return a.exec ();   // 开启事件序列,等待信号槽的处理
}

结果如下:

image-20210610124633412

6、调用成员函数

用法大同小异,只要使用 QtConcurrent::run()的第三个原型函数即可。

代码:

#include <QApplication>
#include <windows.h>
#include <QtConcurrent>
#include <QtCore>

class Test{		// 声明一个类
 public:
  int getCount(int n){			
    qDebug() << "start" << QThread::currentThread ();
    int i = 0;
    while (i < n) {
      qDebug() << i;
      Sleep(1000); 
      ++i;
    }
    qDebug() << "end" << QThread::currentThread ();
    return n;
  }
};

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  qDebug() << "start" << QThread::currentThread ();
  Test t;		// 定义Test类对象
  QFuture<int> f = QtConcurrent::run( &t,&Test::getCount, 4 );// 传入对象地址
  QFutureWatcher<int> w;
  w.setFuture (f);
  QObject::connect (&w,&QFutureWatcher<int>::finished,[&]{
    qDebug() << QThread::currentThread ();
    qDebug()<< f.result ()  << f.resultCount () ;
    a.quit ();    // 主动退出,否则进程一直在循环
  });
  qDebug() << "end" << QThread::currentThread ();
  return a.exec ();   // 开启事件序列,等待信号槽的处理
}

代码结果和第5项一样,截图略。

总结

如果函数有返回值,并用 QFuture 查询了返回值,这个操作会导致阻塞线程。

  • 21
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Python 中有许多方法可以执行并发(concurrent)操作。下面是一个使用多线程(threading)模块的示例: ```python import threading def function_1(): # 执行函数 1 的代码 print("Function 1") def function_2(): # 执行函数 2 的代码 print("Function 2") # 创建两个线程 thread_1 = threading.Thread(target=function_1) thread_2 = threading.Thread(target=function_2) # 启动两个线程 thread_1.start() thread_2.start() # 等待两个线程结束 thread_1.join() thread_2.join() # 所有线程执行完毕后,程序继续执行 print("Done!") ``` 在这个子中,我们使用了 threading 模块中的 Thread 类来创建两个线程,并设置它们的 target 属性为要执行的函数。然后,我们使用 start() 方法启动这两个线程。最后,我们使用 join() 方法等待这两个线程结束。 如果你希望使用其他方法来执行并发操作,如进程(processes)或协程(coroutines),可以查看 Python 的 multiprocessing 和 asyncio 模块。 ### 回答2: Python提供了多种方法来实现并发执行两个函数示例。下面以使用`threading`模块和`multiprocessing`模块为进行说明。 1. 使用`threading`模块实现并发执行两个函数示例: ```python import threading def func1(): # 第一个函数的逻辑 pass def func2(): # 第二个函数的逻辑 pass if __name__ == '__main__': # 创建两个线程并指定目标函数 t1 = threading.Thread(target=func1) t2 = threading.Thread(target=func2) # 启动线程 t1.start() t2.start() # 等待线程执行完毕 t1.join() t2.join() ``` 在这个示例中,通过创建两个`Thread`对象,并分别指定目标函数为`func1`和`func2`,然后使用`start`方法启动这两个线程。使用`join`方法等待两个线程执行完毕。 2. 使用`multiprocessing`模块实现并发执行两个函数示例: ```python import multiprocessing def func1(): # 第一个函数的逻辑 pass def func2(): # 第二个函数的逻辑 pass if __name__ == '__main__': # 创建两个进程对象并指定目标函数 p1 = multiprocessing.Process(target=func1) p2 = multiprocessing.Process(target=func2) # 启动进程 p1.start() p2.start() # 等待进程执行完毕 p1.join() p2.join() ``` 在这个示例中,通过创建两个`Process`对象,并分别指定目标函数为`func1`和`func2`,然后使用`start`方法启动这两个进程。使用`join`方法等待两个进程执行完毕。 这两种方法都可以并发执行两个函数,但是线程是在同一个进程中执行的,而进程则是在不同的进程中执行的。选择使用哪种方法取决于你的具体需求和情况。 ### 回答3: Python的并发执行可以使用多线程或者协程来实现。下面我将分别以多线程和协程的方式给出一个示例。 1. 多线程示例: ```python import threading import time def func1(): print("开始执行函数1") time.sleep(3) print("函数1执行完毕") def func2(): print("开始执行函数2") time.sleep(2) print("函数2执行完毕") if __name__ == "__main__": t1 = threading.Thread(target=func1) t2 = threading.Thread(target=func2) t1.start() t2.start() t1.join() t2.join() print("主线程结束") ``` 在上面的示例中,我们定义了两个函数`func1`和`func2`,分别用于执行一些任务。通过创建两个线程`t1`和`t2`,并将对应的函数作为参数传递给`Thread`类,我们可以实现这两个函数并发执行。在`main`函数中,我们调用了`start`方法来启动这两个线程,然后通过`join`方法等待线程执行完毕,最后主线程结束。 2. 协程示例: ```python import asyncio async def func1(): print("开始执行函数1") await asyncio.sleep(3) print("函数1执行完毕") async def func2(): print("开始执行函数2") await asyncio.sleep(2) print("函数2执行完毕") if __name__ == "__main__": loop = asyncio.get_event_loop() tasks = [func1(), func2()] loop.run_until_complete(asyncio.wait(tasks)) print("主协程结束") ``` 在上面的示例中,我们定义了两个协程`func1`和`func2`,同样用于执行一些任务。通过创建一个事件循环`loop`,然后将这两个协程包装成任务对象`tasks`,我们可以使用`run_until_complete`方法来运行这些任务。最后主协程执行完毕,事件循环结束。 以上就是使用多线程和协程实现Python并发执行两个函数示例。两种方式各有特点,可以根据具体的需求选择合适的方式来实现并发执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值