QFuture 类

template <typename T> class QFuture

QFuture 类代表了异步计算的结果。 更多...

头文件 #include <QFuture>
CMakefind_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmakeQT += core

注意: 本类中所有函数都是线程安全的,以下函数除外

公共类型

公共函数

QFuture()
QFuture(const QFuture<T> &other)
~QFuture()
QFuture<T>::const_iteratorbegin() const
voidcancel()
QFuture<T>::const_iteratorconstBegin() const
QFuture<T>::const_iteratorconstEnd() const
QFuture<T>::const_iteratorend() const
boolisCanceled() const
boolisFinished() const
boolisResultReadyAt(int index) const
boolisRunning() const
boolisStarted() const
(since 6.0) boolisSuspended() const
(since 6.0) boolisSuspending() const
(since 6.0) boolisValid() const
(since 6.0) QFuture<T>onCanceled(Function &&handler)
(since 6.1) QFuture<T>onCanceled(QObject *context, Function &&handler)
(since 6.0) QFuture<T>onFailed(Function &&handler)
(since 6.1) QFuture<T>onFailed(QObject *context, Function &&handler)
intprogressMaximum() const
intprogressMinimum() const
QStringprogressText() const
intprogressValue() const
Tresult() const
TresultAt(int index) const
intresultCount() const
QList<T>results() const
voidresume()
(since 6.0) voidsetSuspended(bool suspend)
(since 6.0) void挂起()
(从6.0开始) TtakeResult()
(从6.0开始) QFuture<QFuture<T>::ResultType<Function>>then(Function &&function)
(从6.0开始) QFuture<QFuture<T>::ResultType<Function>>then(QtFuture::Launch policy, Function &&function)
(从6.0开始) QFuture<QFuture<T>::ResultType<Function>>then(QThreadPool *pool, Function &&function)
(从6.1开始) QFuture<QFuture<T>::ResultType<Function>>then(QObject *context, Function &&function)
(since 6.0) voidtoggleSuspended()
(从6.4开始) QFuture<U>unwrap()
voidwaitForFinished()
QFuture<T> &operator=(const QFuture<T> &other)

详细描述

QFuture 允许线程等待一个或多个将在未来某个时间点准备就绪的结果。结果可以是任何具有默认构造函数、拷贝构造函数和可能还有移动构造函数的类型。如果调用 result()、resultAt()、results() 或 takeResult() 函数时结果不可用,QFuture 将等待直到结果变为可用。您可以使用 isResultReadyAt() 函数来确定结果是否已准备好。对于报告超过一个结果的 QFuture 对象,resultCount() 函数返回连续结果的数量。这意味着始终可以从 0 到 resultCount() 迭代结果。 takeResult() 使未来失去有效性,并且任何尝试从未来访问结果或结果都将导致未定义的行为。 isValid() 告诉您是否可以访问结果。

QFuture 提供了一个 Java 风格迭代器 (QFutureIterator) 以及一个 STL 风格迭代器 (QFuture::const_iterator)。使用这些迭代器是访问未来结果的另一种方式。

如果需要将一个异步计算的结果传递给另一个,QFuture 提供了一种方便的方式使用 then() 将多个连续的计算链接起来。可以通过 onCanceled() 添加一个处理器,在 QFuture 被取消时被调用。此外,可以使用 onFailed() 来处理链中出现任何失败情况。请注意,QFuture 依赖于异常来进行错误处理。如果使用异常不是一个选项,仍然可以通过让错误类型成为 QFuture 类型的组成部分来表示 QFuture 的错误状态。例如,您可以使用 std::variant、std::any 或类似的类型来保存结果或错误,或者创建您自己的自定义类型。

下面的示例演示了在没有使用异常的情况下如何进行错误处理。假设我们想要向一个网络位置发送请求来获取一个大型文件。然后我们想要将其写入文件系统,并在成功的情况下返回其位置。这两个操作可能会以不同的错误失败。所以,我们使用 std::variant 保存结果或错误。

using NetworkReply = std::variant<QByteArray, QNetworkReply::NetworkError>;

enum class IOError { FailedToRead, FailedToWrite };
using IOResult = std::variant<QString, IOError>;

我们使用 then() 将两个操作结合起来

QFuture<IOResult> future = QtConcurrent::run([url] {
        ...
        return NetworkReply(QNetworkReply::TimeoutError);
}).then([](NetworkReply reply) {
    if (auto error = std::get_if<QNetworkReply::NetworkError>(&reply))
        return IOResult(IOError::FailedToRead);

    auto data = std::get_if<QByteArray>(&reply);
    // try to write *data and return IOError::FailedToWrite on failure
    ...
});

auto result = future.result();
if (auto filePath = std::get_if<QString>(&result)) {
    // do something with *filePath
else
    // process the error

可以以任何顺序连接多个连续和处理器。例如

QFuture<int> testFuture = ...;
auto resultFuture = testFuture.then([](int res) {
    // Block 1
}).onCanceled([] {
    // Block 2
}).onFailed([] {
    // Block 3
}).then([] {
    // Block 4
}).onFailed([] {
    // Block 5
}).onCanceled([] {
    // Block 6
});

根据 testFuture 的状态(已取消、有异常或有结果),将会调用下一个 onCanceled()、onFailed() 或 then()。因此如果 testFuture 执行成功,将调用 Block 1。如果它同样成功,将调用下一个 then()(Block 4)。如果 testFuture 被取消或因异常失败,将分别调用 Block 2Block 3。之后将调用下一个 then(),故事重复。

注意: 如果调用 Block 2 并引发异常,将由以下 onFailed()(Block 3)处理。如果将 onFailed() 和 onCanceled() 的顺序颠倒,异常状态将会传播到下一个后续处理,并最终在 Block 5 中捕获。

在下一个示例中,删除了第一个 onCanceled()(Block 2

QFuture<int> testFuture = ...;
auto resultFuture = testFuture.then([](int res) {
    // Block 1
}).onFailed([] {
    // Block 3
}).then([] {
    // Block 4
}).onFailed([] {
    // Block 5
}).onCanceled([] {
    // Block 6
});

如果 testFuture 被取消,其状态将传播到下一个 then(),该 then() 也将被取消。因此,在这种情况下将调用 Block 6

未来只能有一个后续操作。考虑以下示例

QPromise<int> p;

QFuture<int> f1 = p.future();
f1.then([](int) { qDebug("first"); });

QFuture<int> f2 = p.future();
f2.then([](int) { qDebug("second"); });

p.start();
p.addResult(42);
p.finish();

在这种情况下,f1f2 实质上是相同的 QFuture 对象,因为它们共享相同的状态。因此,在 f2 上调用 then 将会覆盖为 f1 指定的后续操作。所以,当这段代码执行时,只会打印出 "second"

QFuture 还提供了与正在运行的计算进行交互的方式。例如,可以使用 cancel() 函数取消计算。要暂停或恢复计算,使用 setSuspended() 函数或以下便捷函数之一:suspendresumetoggleSuspended。请注意,并非所有运行中的异步计算都可以取消或暂停。例如,由 QtConcurrent::run() 返回的未来对象无法取消;但由 QtConcurrent::mappedReduced() 返回的未来对象可以。

进度信息由 progressValueprogressMinimumprogressMaximumprogressText 函数提供。waitForFinished 函数会导致调用线程阻塞并等待计算完成,确保所有结果都可用。

可以使用 isCanceledisStartedisFinishedisRunningisSuspendingisSuspended 函数查询由 QFuture 表示的计算的状态。

QFuture<void>被专门设计为不包含任何结果检索函数。任何 QFuture<T> 都可以赋值到 QFuture<void> 或与之复制。如果只需要状态或进度信息,而不是实际的结果数据,这很有用。

要使用信号和槽交互正在运行的任务,请使用 QFutureWatcher

您还可以使用 QtFuture::connect() 将信号连接到一个 QFuture 对象,当信号被发射时,该对象将被解决。这允许像处理 QFuture 对象一样处理信号。例如,如果您将其与 then() 结合使用,您可以向信号附加多个后续操作,这些操作在同一线程或新线程中调用。

可以使用QtFuture::whenAll() 和 QtFuture::whenAny() 函数来组合多个未来对象,并跟踪它们中的最后一个或第一个何时完成。

可以使用便利函数QtFuture::makeReadyVoidFuture()、QtFuture::makeReadyValueFuture()、QtFuture::makeReadyRangeFuture() 和 QtFuture::makeExceptionalFuture() 来创建带有值的 QFuture 对象或持有异常的 QFuture 对象。

注意:一些 API(参阅 QFuture::then() 或各种 QtConcurrent 方法重载)允许将计算调度到特定的线程池。然而,QFuture 实现了一个工作窃取算法来防止死锁并优化线程使用。因此,计算可以直接在请求 QFuture 结果的线程中执行。

注意:要开始一个计算并将结果存储在 QFuture 中,请使用 QPromiseQt Concurrent 框架中的 API 之一。

参见:QPromiseQtFuture::connect()、QtFuture::makeReadyVoidFuture()、QtFuture::makeReadyValueFuture()、QtFuture::makeReadyRangeFuture()、QtFuture::makeExceptionalFuture()、QFutureWatcherQt Concurrent

成员类型文档

QFuture::ConstIterator

Qt 风格的同义词 QFuture::const_iterator

成员函数文档

QFuture::QFuture()

构建一个空的、已取消的未来对象。

QFuture::QFuture(const QFuture<T> &other)

构建 other 的副本。

参见:operator=()。

QFuture::~QFuture()

销毁未来对象。

注意,这既不等待也不取消异步计算。当您需要确保计算在未来对象被销毁之前完成时,请使用 waitForFinished() 或 QFutureSynchronizer

模板 QFuture<T>::const_iterator QFuture::begin() const

返回一个指向未来对象中第一个结果的常量 STL 风格的迭代器

参见:constBegin() 和 end()。

void QFuture::cancel()

取消由此未来对象表示的异步计算。请注意,取消是异步的。当您需要同步取消时,在调用 cancel() 后使用 waitForFinished()。

取消操作后,可以访问当前可用的结果,但在调用此函数后,将 不会 出现新结果。任何监视此未来对象的 QFutureWatcher 对象将不会在已取消的未来对象上发送进度和结果就绪信号。

请注意,并非所有正在运行的非阻塞计算都可以取消。例如,QtConcurrent::run() 返回的未来对象无法取消;但 QtConcurrent::mappedReduced() 返回的未来对象可以取消。

返回一个指向未来对象中第一个结果的常量 STL 风格的迭代器

相关条目:begin() 和 constEnd().

返回一个指向未来中最后一个结果之后的虚拟结果的常量STL样式迭代器

参见:constBegin() 和 end()。

返回一个指向未来中最后一个结果之后的虚拟结果的常量STL样式迭代器

相关条目:begin() 和 constEnd().

bool QFuture::isCanceled() const

如果异步计算已被cancel()函数取消,则返回true;否则返回false

请注意,即使此函数返回true,计算也可能仍在进行中。有关更多信息,请参阅cancel

bool QFuture::isFinished() const

如果由此未来表示的非阻塞计算已完成,则返回true;否则返回false

如果索引为index的结果立即可用,则返回true;否则返回false

注意: 如果此QFutureisValid()返回false,调用isResultReadyAt()会导致未定义的行为。

相关条目:resultAt(),resultCounttakeResult

bool QFuture::isRunning() const

如果由此未来表示的非阻塞计算当前正在运行,则返回true;否则返回false

bool QFuture::isStarted() const

如果由此未来表示的非阻塞计算已启动,则返回true;否则返回false

[since 6.0] bool QFuture::isSuspended() const

如果已请求挂起异步计算,并且它正在生效(即不再期望更多的结果或进度变化),则返回true

此函数自Qt 6.0开始引入。

相关条目:setSuspended(),toggleSuspendedisSuspending

[since 6.0] bool QFuture::isSuspending() const

如果异步计算已被suspend()函数挂起,但尚未暂时停止,计算仍在进行,则返回true。否则返回false。

要检查是否实际悬挂,请使用isSuspended()。

此函数自Qt 6.0开始引入。

另请参阅setSuspended()、toggleSuspended()和isSuspended()。

[since 6.0] bool QFuture::isValid() const

如果可以从此QFuture对象访问或获取结果,则返回true。结果从未来中提取后返回false。

此函数自Qt 6.0开始引入。

另请参阅takeResult()、result()、results()和resultAt()。

[since 6.0] 模板 <typename Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture::onCanceled(Function &&handler)

将一个取消处理器附加到此未来。返回的未来将具有与当前相同的状态和结果,除非此未来被取消。处理器是一个可调用对象,它不接收任何参数,并返回此未来打包的类型值。在取消后,返回的未来将包装处理器返回的值。

如果在未来取消之前附加,处理器会在这个报告未来结束的线程中被调用。如果在未来已经被取消后附加处理器,则处理器会立即在执行onCanceled()的线程中被调用。因此,处理器不能总是假定将在哪个线程上运行。如果您想要控制处理器在哪个线程上被调用,请使用接收上下文对象的 overload。

以下示例演示了如何附加取消处理器

QFuture<int> testFuture = ...;
auto resultFuture = testFuture.then([](int res) {
    // Block 1
    ...
    return 1;
}).then([](int res) {
    // Block 2
    ...
    return 2;
}).onCanceled([] {
    // Block 3
    ...
    return -1;
});

如果testFuture被取消,则Block 3将被调用,并且resultFuture的结果将为-1。与testFuture不同,它不会处于已取消状态。这意味着您可以获取其结果、向其添加连续性,等等。

请注意,您还可以通过启动连锁的future来在它们执行时通过future取消连锁。假设在Block 1已经执行时调用了testFuture.cancel()。下一个连锁将检测到已请求取消,因此将跳过Block 2,并将取消处理器(Block 3)调用。

注意:此方法返回一个表示连锁结果的新QFuture。取消此QFuture本身不会触发连锁中的取消处理器。这意味着如果您调用resultFuture.cancel(),则不会调用Block 3:因为resultFuture是附加取消处理器到testFuture后获得的未来,没有将取消处理器附加到resultFuture本身。只有取消testFuture或在onCancelled()调用之前附加的连续ette中返回的未来才能触发Block 3

此函数自Qt 6.0开始引入。

另请参阅 then() 和 onFailed()。

[自6.1以来] 模板 <typename Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture::onCanceled(QObject *context, Function &&handler)

这是一个重载函数。

为此将取消处理器附加到此将在此将取消附加到此将取消,以在取消时调用它。处理器是一个无参数的可调用对象。它将在上下文对象的线程中被调用。如果需要在该特定线程中处理取消,这可能很有用。

如果上下文在链完成之前被摧毁,则此将取消。

注意:在调用此方法时,应确保上下文在设置链过程中始终存在。

有关其他重载的详细说明,请参阅处理器的文档。

该功能是在Qt 6.1中引入的。

另请参阅 then() 和 onFailed()。

[自6.0以来] 模板 <typename Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture::onFailed(Function &&handler)

为此将失败处理器附加到此,以处理任何异常。除非此将失败抛出异常,否则返回的未来将与此时的状态和结果相同。

处理器是无参数或有参数的可调用对象,以过滤特定错误类型,类似于捕获语句。它返回由此返回的值。失败后,返回的未来包装处理器返回的值。

处理器只有在抛出异常时才会被调用。如果在此处理器附加之后抛出了异常,则在报告未来完成的线程中将执行处理器。如果在此未来失败后附加处理器,它将立即在执行onFailed()的线程中调用。因此,处理器无法始终假设它将在哪个线程上运行。如果您想控制调用处理器所在的线程,请使用接受上下文对象的泛型重载。

以下示例演示了如何附加失败处理器:

QFuture<int> future = ...;
auto resultFuture = future.then([](int res) {
    ...
    throw Error();
    ...
}).onFailed([](const Error &e) {
    // Handle exceptions of type Error
    ...
    return -1;
}).onFailed([] {
    // Handle all other types of errors
    ...
    return -1;
});

auto result = resultFuture.result(); // result is -1

如果有多个处理器已附加,则将与抛出异常类型匹配的第一个处理器被调用。例如:

QFuture<int> future = ...;
future.then([](int res) {
    ...
    throw std::runtime_error("message");
    ...
}).onFailed([](const std::exception &e) {
    // This handler will be invoked
}).onFailed([](const std::runtime_error &e) {
    // This handler won't be invoked, because of the handler above.
});

如果没有与抛出异常类型匹配的处理器,则异常将传播到结果未来。

QFuture<int> future = ...;
auto resultFuture = future.then([](int res) {
    ...
    throw Error("message");
    ...
}).onFailed([](const std::exception &e) {
    // Won't be invoked
}).onFailed([](const QException &e) {
    // Won't be invoked
});

try {
    auto result = resultFuture.result();
} catch(...) {
    // Handle the exception
}

注意:您始终可以附加一个无参数的处理程序,以处理所有异常类型并避免编写try-catch块。

此函数自Qt 6.0开始引入。

另请参阅 then() 和 onCanceled

[自6.1以来] 模板 <typename Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture::onFailed(QObject *context, Function &&handler)

这是一个重载函数。

将错误处理器附加到该QFuture对象,用于处理该QFuture产生的任何异常,或者它已经产生的异常。返回类型与该QFuture相同的QFuture。只有在发生异常的情况下,处理器才会在上下文对象的线程中调用。如果在特定线程中处理失败情况非常有用。例如

// somewhere in the main thread
auto future = QtConcurrent::run([] {
    // This will run in a separate thread
    ...
    throw std::exception();
}).onFailed(this, [] {
   // Update UI elements
});

附加到QtConcurrent::run的错误处理器更新UI元素,无法从非GUI线程调用。所以提供此上下文给.onFailed(),以确保它将在主线程中调用。

如果上下文在链完成之前被摧毁,则此将取消。

注意:在调用此方法时,应确保上下文在设置链过程中始终存在。

有关其他重载的详细说明,请参阅处理器的文档。

该功能是在Qt 6.1中引入的。

另请参阅 then() 和 onCanceled

int QFuture::progressMaximum() const

返回的最大progressValue值。

另请参阅 progressValue()和progressMinimum()。

int QFuture::progressMinimum() const

返回最小progressValue值。

另请参阅 progressValue()和progressMaximum

QString QFuture::progressText() const

返回异步计算报告的进度(可选)文本表示形式。

请注意,并非所有计算都提供进度的文本表示形式,因此此函数可能返回空字符串。

int QFuture::progressValue() const

返回当前进度值,该值在progressMinimum()和progressMaximum()之间。

另请参阅 progressMinimum()和progressMaximum

模板 <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::result() const

返回QFuture中的第一个结果。如果结果不可立即获得,此函数将阻塞并等待结果可用。这是调用resultAt(0)的便捷方法。请注意,result()返回内部存储结果的副本。如果T是移动类型,或者您不希望复制结果,请使用takeResult()。

注意: 如果此QFutureisValid()返回false,则调用result()会导致未定义的行为。

另请参阅 resultAt()、results()和takeResult

模板 <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::resultAt(int index) const

返回位于未来中索引处的结果。如果结果不可立即获得,此函数将阻塞并等待结果可用。

注意: 如果此QFutureisValid()返回false,则调用resultAt()会导致未定义的行为。

另请参阅 result()、results()、takeResult()和resultCount

int QFuture::resultCount() const

返回此未来中的连续结果数量。由于结果集可能存在空缺,实际存储的结果数量可能与该值不同。始终可以安全地从0迭代到resultCount()遍历结果。

另请参阅 result(),resultAt(),results(),和takeResult()。

模板 <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QList<T> QFuture::results() const

返回未来中所有结果。如果结果不可立即获得,此函数将阻塞并等待他们变得可用。请注意,results()返回内部存储结果的副本。目前不支持获取移动类型的结果T。但是,您仍然可以使用STL样式迭代器或只读Java样式的迭代器遍历移动结果列表。

注意: 如果此QFutureisValid()返回false,则调用results()将导致未定义的行为。

另请参阅 result(),resultAt(),takeResult(),resultCount(),和isValid()。

void QFuture::resume()

恢复由future()表示的异步计算。这是一个方便的方法,它简单地调用setSuspended(false)。

另请参阅 suspend()。

[since 6.0] void QFuture::setSuspended(bool suspend)

如果suspend为true,则此函数将挂起由future()表示的异步计算。如果计算已经挂起,此函数将不做任何操作。在挂起时,可能仍有正在进行的计算不能被停止。对于这些计算的信号仍会传递。

如果suspend为false,则此函数将恢复异步计算。如果计算之前未挂起,此函数将不做任何操作。

请注意,并非所有计算都可以挂起。例如,由QtConcurrent::run()返回的QFuture不能挂起;但是由QtConcurrent::mappedReduced()返回的QFuture可以。

此函数自Qt 6.0开始引入。

另请参阅 isSuspended(),suspend(),resume(),和toggleSuspended()。

[since 6.0] void QFuture::suspend()

挂起此未来表示的异步计算。这是一个方便的方法,它简单地调用setSuspended(true)。

此函数自Qt 6.0开始引入。

另请参阅 resume()。

[since 6.0] 模板 <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::takeResult()

只有在isValid()返回true时才调用此函数,否则行为未定义。此函数从QFuture对象中取出(移动)第一个结果,当预期只有一个结果时。如果有其他任何结果,则在取出第一个结果后会丢弃。如果结果不能立即可用,此函数将阻塞并等待结果变得可用。《a href="qfuture.html" translate="no">QFuture会尽可能使用移动语义,如果类型不可移动,则会回退到复制构造函数。结果被提取后,《a href="qfuture.html#isValid" translate="no">isValid()将评估为false

注意:QFuture通常允许在不同QFuture对象(以及可能在不同线程)之间共享结果。引入takeResult()是为了使QFuture也能与移动类型(如std::unique_ptr)一起工作,因此它假设只有一个线程可以移动结果,并且只能移动一次。请注意,目前不支持获取所有结果列表。然而,您仍然可以使用STL-style iterators或只读Java-style iterators遍历移动类型的结果列表。

此函数自Qt 6.0开始引入。

另请参阅:result函数、results函数、resultAt函数以及isValid函数。

[since 6.0] 模板 <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(Function &&function)

这是一个重载函数。

将后续操作附加到此未来上,允许在需要的情况下使用Sync策略链式调用多个异步计算。如果此未来有结果(不是QFuture<void>),则function是可调用的,其需要一个与该未来打包的类型的参数。否则,它不接受任何参数。该方法返回一个新QFuture,该废弃物返回的结果类型为function。返回的未来将在附加的后续操作被调用、此未来失败或被取消之前处于未初始化状态。

注意:如果需要在一个单独的线程中启动后续操作,请使用此方法的其他重载。

您可以像这样链式调用多个操作

QFuture<int> future = ...;
future.then([](int res1){ ... }).then([](int res2){ ... })...

或者

QFuture<void> future = ...;
future.then([](){ ... }).then([](){ ... })...

后续操作也可以接受一个QFuture参数(而不是它的值),表示先前的未来。如果,例如QFuture有多个结果,并且用户希望在后续操作中访问它们,这可能很有用。或者用户需要在后续操作中处理先前的未来的异常,以防止中断多个后续操作的链。例如

QFuture<int> future = ...;
    future.then([](QFuture<int> f) {
        try {
            ...
            auto result = f.result();
            ...
        } catch (QException &e) {
            // handle the exception
        }
    }).then(...);

如果先前的未来抛出一个异常,并且没有在后续操作中处理它,则异常将传播到后续操作未来中,允许调用者处理它。

QFuture<int> future = ...;
auto continuation = future.then([](int res1){ ... }).then([](int res2){ ... })...
...
// future throws an exception
try {
    auto result = continuation.result();
} catch (QException &e) {
    // handle the exception
}

在这种情况下,整个后续操作链将中断。

注意:如果此未来被取消,附加到它的后续操作也将被取消。

此函数自Qt 6.0开始引入。

另请参阅:onFailed()和onCanceled()函数。

[自 6.0] 模板 <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(QtFuture::Launch policy, Function &&function)

这是一个重载函数。

将为这个未来附加一个后续操作,允许链接多个异步计算。当代表此未来的异步计算完成时,将根据给定的启动policy调用function。将返回一个表示继续操作结果的新的QFuture

根据policy,后续操作将在与这个未来相同的线程中调用,在一个新线程中,或者将继承这个未来的启动策略和线程池。如果没有指定启动策略(请参阅仅接受可调用对象的重载),则将使用Sync策略。

以下示例中,两个后续操作将在新线程中调用(但属于同一个线程)。

QFuture<int> future = ...;
future.then(QtFuture::Launch::Async, [](int res){ ... }).then([](int res2){ ... });

以下示例中,两个后续操作将使用相同的线程池在新线程中调用。

QFuture<int> future = ...;
future.then(QtFuture::Launch::Async, [](int res){ ... })
      .then(QtFuture::Launch::Inherit, [](int res2){ ... });

有关更多信息,请参阅其他重载的文档,以了解关于function的详细信息。

此函数自Qt 6.0开始引入。

另请参阅:onFailed()和onCanceled()函数。

[自 6.0] 模板 <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(QThreadPool *pool, Function &&function)

这是一个重载函数。

将为这个未来附加一个后续操作,如果需要的话,可以链接多个异步计算。当代表此未来的异步计算完成时,function将被安排在高pool

此函数自Qt 6.0开始引入。

另请参阅:onFailed()和onCanceled()函数。

[自 6.1] 模板 <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(QObject *context, Function &&function)

这是一个重载函数。

将为这个未来附加一个后续操作,如果需要的话,可以链接多个异步计算。当代表此未来的异步计算完成时,function将在这个context对象的线程中调用。这对于需要在任何特定线程中调用继续操作非常有用。例如

// somewhere in the main thread
auto future = QtConcurrent::run([] {
    // This will run in a separate thread
    ...
}).then(this, [] {
   // Update UI elements
});

附加到QtConcurrent::run的继续操作将更新UI元素,不能从非GUI线程中调用。因此,this被提供给.then(),以确保它将调用主线程。

以下也会从相同的上下文中调用继续操作,除非指定了不同的上下文或启动策略

auto future = QtConcurrent::run([] {
    ...
}).then(this, [] {
   // Update UI elements
}).then([] {
    // This will also run in the main thread
});

这是因为默认情况下.then()是从之前的同一个线程中调用的。

但是请注意,如果继续操作在未来的完成后附加,它将立即调用,在执行then()的线程中

QObject *context = ...;
auto future = cachedResultsReady ? QtFuture::makeReadyValueFuture(result)
                                 : QtConcurrent::run([] { /* compute result */});
auto continuation = future.then(context, [] (Result result) {
    // Runs in the context's thread
}).then([] {
    // May or may not run in the context's thread
});

在上面的示例中,如果cachedResultsReadytrue,并且返回了一个就绪的未来,那么有可能第一个.then()在第二个.then()附加之前完成。在这种情况下,它将在当前线程中解决。因此,在不确定的情况下,请明确传递上下文。

如果在链完成之前销毁了上下文,则取消未来。这意味着可能会在上下文不再有效时调用取消处理程序。为此,将上下文捕获为QPointer

QObject *context = ...;
auto future = ...;
auto continuation = future.then(context, [context](Result result) {
                               // ...
                           }).onCanceled([context = QPointer(context)] {
                               if (!context)
                                   return;  // context was destroyed already
                               // handle cancellation
                           });

当上下文对象销毁时,取消操作立即发生。链中的先前的未来不会取消,将继续执行直到完成。

注意:在调用此方法时,应确保上下文在设置链过程中始终存在。

该功能是在Qt 6.1中引入的。

另请参阅:onFailed()和onCanceled()函数。

[自6.0起] void QFuture::toggleSuspended()

切换异步计算的暂停状态。换句话说,如果计算当前正在挂起或已挂起,调用此函数将恢复它;如果计算正在运行,则将其挂起。这是一个调用setSuspended(!(isSuspending() || isSuspended()))的便利方法。

此函数自Qt 6.0开始引入。

另请参阅setSuspended()、suspend()和resume()

[自6.4起] template <typename U> QFuture<U> QFuture::unwrap()

从此QFuture<T>中解包内部未来,其中T是类型QFuture<U>的未来,即此未来的类型为QFuture<QFuture<U>>。例如

QFuture<QFuture<int>> outerFuture = ...;
QFuture<int> unwrappedFuture = outerFuture.unwrap();

unwrappedFuture将在内部未来解包在outerFuture中完成时满足,具有相同的结果或异常,并在报告内部未来完成的同一线程中。如果内部未来被取消,则unwrappedFuture也将被取消。

这在将多个计算串联起来,并且其中一个返回QFuture作为其结果类型时特别有用。例如,假设我们想从URL下载多个图像,缩放图像,并使用QtConcurrent::mappedReduced()将它们减少到单个图像。我们可以编写如下内容

auto downloadImages = [] (const QUrl &url) {
    QList<QImage> images;
    ...
    return images;
};

auto processImages = [](const QList<QImage> &images) {
   return QtConcurrent::mappedReduced(images, scale, reduceImages);
}

auto show = [](const QImage &image) { ... };

auto future = QtConcurrent::run(downloadImages, url)
               .then(processImages)
               .unwrap()
               .then(show);

在此处 QtConcurrent::mappedReduced()返回一个QFuture<QImage>,因此.then(processImages)返回一个QFuture<QFuture<QImage>>。由于show()需要一个QImage作为参数,因此我们不能直接将.then(processImages)的结果传递给它。我们需要调用.unwrap(),这将获取内部未来的结果并将其传递给下一个回调。

在多层嵌套的情况下,.unwrap()将深入到最内层

QFuture<QFuture<QFuture<int>>>> outerFuture;
QFuture<int> unwrappedFuture = outerFuture.unwrap();

此功能自Qt 6.4引入。

void QFuture::waitForFinished()

等待异步计算完成(包括已取消的计算),即直到isFinished()返回true

QFuture<T> &QFuture::operator=(const QFuture<T> &other)

other分配给此未来并返回对此未来的引用。

© 2024 Qt公司有限公司。包含在此处的文档贡献是各自所有者的版权。提供的文档受GNU自由文档许可版1.3的条款约束,由自由软件基金会发布。Qt及其标志是芬兰和/或其他国家的Qt公司有限公司的商标。所有其他商标均为其各自所有者的财产。