自定义创建QFuture

Custom creation of QFuture

本文关键字:QFuture 创建 自定义      更新时间:2023-10-16

我在QtConcurrent中遇到了一个非常奇怪的问题,主要是因为奇怪的编程欲望,也许这只是一个XY问题,但。。。

所以,这是我的代码,试图与数据库通信,实际上是一个后端代码(在Qt上,是的(。它必须快速工作并处理一些请求,所以我需要一个线程池。众所周知,我认为建立连接本身是一项非常耗时的操作,因此需要持久的数据库连接来产生持久的线程(QSqlDatabase不能在线程之间移动(。此外,想要异步请求处理也是很自然的,因此需要一种简单的方法将它们传递给持久线程。

没有什么太复杂的,让我们假设已经存在一些类似。。。


// That's what I want for now
QFuture<int> res = workers[i]->async(param1, param2);
// OR
// That's what I DO NOT want to get
workers[i]->async(param1, param2, [](QFuture<int> res) { // QFuture to pass exceptions
// callback here
});

这是可以肯定的。为什么不std::future?好吧,使用QFutureWatcher要容易得多,它是通知结果准备就绪的信号。纯C++通知解决方案muuuch更为复杂,回调也需要在类层次结构中拖动。显然,每个工作线程都用DB连接来连接线程。

好吧,所有这些都可以写出来,但是。。。自定义线程池将意味着没有QtConcurrent的便利性,创建QFuture以便由自定义工作程序返回似乎只有风险的方法。QThreadPool没有用,因为在其中创建持久的可运行程序将是一个大故事。更重要的是,我简要描述的样板将是某种项目的核心,在许多地方使用,而不是一个100个手工线程可以轻易取代的东西。

简而言之:如果我能为我的结果构造一个QFuture,问题就会解决。有人能给我指一个解决方案或变通办法吗?如果有什么好主意,我将不胜感激。


UPD:

@VladimirBershov提供了一个很好的实现观察者模式的现代解决方案。经过一些谷歌搜索,我发现了一个QPromise库。当然,构建一个自定义的QFuture仍然很麻烦,只能通过未记录的QFutureInterface类来完成,但据我所判断,仍然有一些"类似承诺"的解决方案使异步调用更加整洁。

您可以使用AsyncFuture库作为自定义QFuture创建工具或创意来源:

AsyncFuture-像Promise对象一样使用QFuture

QFuture与QtConcurrent一起用于表示异步计算。它是多线程编程。但它的使用仅限于线程,它不适用于QObject。通过Q未来观察者。

AsyncFuture旨在增强功能,以提供更好的方式将其用于异步编程。它提供了Promise对象类接口。这个项目的灵感来自AsynQt和RxCpp。

功能:

  • 将来自QObject的信号转换为QFuture对象
  • 将不同类型的多个期货组合为一个期货对象
  • 像Promise对象一样使用Future
  • 可链接回调-高级多线程编程模型

将来自QObject的信号转换为QFuture对象:

#include "asyncfuture.h"
using namespace AsyncFuture;
// Convert a signal from QObject into a QFuture object
QFuture<void> future = observe(timer, &QTimer::timeout).future();
/* Listen from the future without using QFutureWatcher<T>*/
observe(future).subscribe([]() {
// onCompleted. It is invoked when the observed future is finished successfully
qDebug() << "onCompleted";
},[]() {
// onCanceled
qDebug() << "onCancel";
});

我的想法是使用线程池,每个线程最多可使用1个线程。

QThreadPool* persistentThread = new QThreadPool; // no need to write custom thread pool
persistentThread->setMaxThreadCount(1);
persistentThread->setExpiryTimeout(-1);

然后

QFuture<int> future_1 = QtConcurrent::run(persistentThread, func_1);
QFuture<int> future_2 = QtConcurrent::run(persistentThread, func_2);

func_2将在func_1之后在同一个"持久"线程中执行。