QFuture 类
template <typename T> class QFutureQFuture 类代表了异步计算的结果。 更多...
头文件 | #include <QFuture> |
CMake | find_package(Qt6 REQUIRED COMPONENTS Core) target_link_libraries(mytarget PRIVATE Qt6::Core) |
qmake | QT += core |
- 所有成员列表,包括继承的成员
- 已弃用成员
- QFuture 是线程类的一部分 Threading Classes.
注意: 本类中所有函数都是线程安全的,以下函数除外
公共类型
公共函数
QFuture() | |
QFuture(const QFuture<T> &other) | |
~QFuture() | |
QFuture<T>::const_iterator | begin() const |
void | cancel() |
QFuture<T>::const_iterator | constBegin() const |
QFuture<T>::const_iterator | constEnd() const |
QFuture<T>::const_iterator | end() const |
bool | isCanceled() const |
bool | isFinished() const |
bool | isResultReadyAt(int index) const |
bool | isRunning() const |
bool | isStarted() const |
(since 6.0) bool | isSuspended() const |
(since 6.0) bool | isSuspending() const |
(since 6.0) bool | isValid() 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) |
int | progressMaximum() const |
int | progressMinimum() const |
QString | progressText() const |
int | progressValue() const |
T | result() const |
T | resultAt(int index) const |
int | resultCount() const |
QList<T> | results() const |
void | resume() |
(since 6.0) void | setSuspended(bool suspend) |
(since 6.0) void | 挂起() |
(从6.0开始) T | takeResult() |
(从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) void | toggleSuspended() |
(从6.4开始) QFuture<U> | unwrap() |
void | waitForFinished() |
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 2
或 Block 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();
在这种情况下,f1
和 f2
实质上是相同的 QFuture 对象,因为它们共享相同的状态。因此,在 f2
上调用 then 将会覆盖为 f1
指定的后续操作。所以,当这段代码执行时,只会打印出 "second"
。
QFuture 还提供了与正在运行的计算进行交互的方式。例如,可以使用 cancel() 函数取消计算。要暂停或恢复计算,使用 setSuspended() 函数或以下便捷函数之一:suspend、resume 或 toggleSuspended。请注意,并非所有运行中的异步计算都可以取消或暂停。例如,由 QtConcurrent::run() 返回的未来对象无法取消;但由 QtConcurrent::mappedReduced() 返回的未来对象可以。
进度信息由 progressValue、progressMinimum、progressMaximum 和 progressText 函数提供。waitForFinished 函数会导致调用线程阻塞并等待计算完成,确保所有结果都可用。
可以使用 isCanceled、isStarted、isFinished、isRunning、isSuspending 或 isSuspended 函数查询由 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 中,请使用 QPromise 或 Qt Concurrent 框架中的 API 之一。
参见:QPromise、QtFuture::connect()、QtFuture::makeReadyVoidFuture()、QtFuture::makeReadyValueFuture()、QtFuture::makeReadyRangeFuture()、QtFuture::makeExceptionalFuture()、QFutureWatcher 和 Qt Concurrent。
成员函数文档
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() 返回的未来对象可以取消。
QFuture<T>::const_iterator QFuture::constBegin() const
返回一个指向未来对象中第一个结果的常量 STL 风格的迭代器。
QFuture<T>::const_iterator QFuture::constEnd() const
返回一个指向未来中最后一个结果之后的虚拟结果的常量STL样式迭代器。
参见:constBegin() 和 end()。
QFuture<T>::const_iterator QFuture::end() const
返回一个指向未来中最后一个结果之后的虚拟结果的常量STL样式迭代器。
bool QFuture::isCanceled() const
如果异步计算已被cancel()函数取消,则返回true
;否则返回false
。
请注意,即使此函数返回true
,计算也可能仍在进行中。有关更多信息,请参阅cancel。
bool QFuture::isFinished() const
如果由此未来表示的非阻塞计算已完成,则返回true
;否则返回false
。
bool QFuture::isResultReadyAt(int index) const
如果索引为index
的结果立即可用,则返回true
;否则返回false
。
相关条目:resultAt(),resultCount和takeResult。
bool QFuture::isRunning() const
如果由此未来表示的非阻塞计算当前正在运行,则返回true
;否则返回false
。
bool QFuture::isStarted() const
如果由此未来表示的非阻塞计算已启动,则返回true
;否则返回false
。
[since 6.0]
bool QFuture::isSuspended() const
如果已请求挂起异步计算,并且它正在生效(即不再期望更多的结果或进度变化),则返回true
。
此函数自Qt 6.0开始引入。
相关条目:setSuspended(),toggleSuspended和isSuspending。
[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开始引入。
[自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中引入的。
[自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()。
另请参阅 resultAt()、results()和takeResult。
模板 <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::resultAt(int index) const
返回位于未来中索引处的结果。如果结果不可立即获得,此函数将阻塞并等待结果可用。
另请参阅 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样式的迭代器遍历移动结果列表。
另请参阅 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 });
在上面的示例中,如果cachedResultsReady
为true
,并且返回了一个就绪的未来,那么有可能第一个.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>>
。例如
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()
将深入到最内层
此功能自Qt 6.4引入。
void QFuture::waitForFinished()
等待异步计算完成(包括已取消的计算),即直到isFinished()返回true
。
QFuture<T> &QFuture::operator=(const QFuture<T> &other)
将other
分配给此未来并返回对此未来的引用。
© 2024 Qt公司有限公司。包含在此处的文档贡献是各自所有者的版权。提供的文档受GNU自由文档许可版1.3的条款约束,由自由软件基金会发布。Qt及其标志是芬兰和/或其他国家的Qt公司有限公司的商标。所有其他商标均为其各自所有者的财产。