QtのQFuture
Qts Qfuture
QFutureクラスは、非同期計算の結果を表します。
計算を開始するには、Qtの並行フレームワークのAPIの1つを使用します。
QFutureを使用すると、スレッドを1つ以上の結果と同期させることができます。これらの結果は、後で準備が整います。これは、デフォルトのコンストラクターとコピーコンストラクターを持つ任意のタイプにすることができます。 result()、resultAt()、またはresults()関数が呼び出されたときに結果が使用できない場合、QFutureは、isResultReadyAt()関数を使用して結果の準備ができているかどうかを確認し、結果が使用可能になるまで待機します。
進行状況情報は、progressValue()、progressMinimum()、progressMaximum()、およびprogressText()関数によって提供されます。
基本的な使い方
別のスレッドで関数を実行するには、QtConcurrent :: run()を使用します。
#include #include #include void hello(const QString &name) { qDebug() << 'Hello' << name << 'from' << QThread::currentThread() } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv) qDebug() << 'Main Thread' << QThread::currentThread() // call hello() in a separate thread QFuture f1 = QtConcurrent::run(hello, QString('Qter')) QFuture f2 = QtConcurrent::run(hello, QString('Pythoner')) // Block the calling thread and wait for the calculation to complete, making sure all results are available f1.waitForFinished() f2.waitForFinished() }
明らかに、メインスレッドは他の2つのスレッドとは異なります。
QFuture
結果を含まない関数の取得専用QFuture
割り当てまたはコピー可能QFuture
。これは、ステータスまたは進行状況情報のみが必要で、実際の結果データは必要ない場合に役立ちます。
高度な操作
QFutureは、進行中の非同期呼び出しと対話するためのいくつかのメソッドも提供します。たとえば、cancel()関数を使用して計算をキャンセルし、計算を一時停止します。setPaused()関数、またはpause()、resume()、togglePaused()コンビニエンス関数のいずれかを使用します。
アシスタントには非常に重要な文があります。
すべての非同期計算をキャンセルまたは一時停止できるわけではないことに注意してください。たとえば、QtConcurrent :: run()によって返される未来はキャンセルできませんが、QtConcurrent :: mappedReduced()によって返される未来はキャンセルできます。
これは、すべての非同期計算をキャンセルまたは一時停止できるわけではないことを意味します。たとえば、QtConcurrent :: run()によって返されるfutureはキャンセルできませんが、QtConcurrent :: mappedReduced()は返されます。
画像のセットをスケーリングする例を見てみましょう。
#include #include #include #include QImage scale(const QImage &image) { qDebug() << 'Scaling image in thread' << QThread::currentThread() return image.scaled(QSize(100, 100), Qt::IgnoreAspectRatio, Qt::SmoothTransformation) } int main(int argc, char *argv[]) { QGuiApplication app(argc, argv) const int imageCount = 20 // Create a list containing imageCount images QList images for (int i = 0 i < imageCount ++i) images.append(QImage(1600, 1200, QImage::Format_ARGB32_Premultiplied)) // Apply a scale function (zoom) to each image using QtConcurrent::mapped QFuture thumbnails = QtConcurrent::mapped(images, scale) // pause calculation thumbnails.pause() qDebug() << 'isPaused' << thumbnails.isPaused() // resume calculation if(thumbnails.isPaused()) { thumbnails.resume() qDebug() << 'isStarted' << thumbnails.isPaused() } // Block the calling thread and wait for the calculation to complete, making sure all results are available thumbnails.waitForFinished() // return all results of future QList list = thumbnails.results() foreach (QImage image, list) { qDebug() << image } qDebug() << '********************' / / Returns the number of results in future int nCount = thumbnails.resultCount() for (int i = 0 i < nCount ++i) { QImage image = thumbnails.resultAt(i) qDebug() << image } return 0 }
効果を示すために、mapped()を呼び出した後、pause()を使用して計算を一時停止し、次にisPaused()を使用してQFutureで表される計算状態を照会します。ステータスは、isCanceled()、isStarted()、isFinished()、isRunning()、またはisPaused()関数を使用して照会できます。
注:isPaused()がtrueを返した場合でも、計算が実行されている可能性があります。
将来的に結果にアクセスするには、インデックスの場所を使用できます。一部のQFutureメンバー関数は、最初の引数としてインデックスを取り(例:resultAt())、イテレーターなしでアクセスできるようにします。
複数の結果を持つQFutureオブジェクトの場合、resultCount()関数は連続した結果の数を返します。これは、0からresultCount()までの結果が常に安全であることを意味します。
イテレータ
QFutureは、Javaスタイルのイテレーター(QFutureIterator)とSTLスタイルのイテレーター(QFuture :: const_iterator)を提供します。
Javaスタイルのイテレータ:高度で使いやすい一方で、効率がやや劣ります。
STLスタイルのイテレータ:低レベルで、使用するのは面倒ですが、一方で、わずかに高速です。 STLを理解している人は、すぐに始めることができます。
これらのイテレータを使用することは、将来結果にアクセスするためのもう1つの方法です。
QFutureIterator
QFutureIteratorクラスは、QFuture用のJavaスタイルの定数イテレーターを提供します。
QFutureIteratorを使用すると、QFutureをトラバースできます。注:QFutureには変更可能なイテレーターはありません(他のJavaスタイルのイテレーターとは異なります)。
QFutureIteratorコンストラクターは、引数としてQFutureを使用します。構築後、イテレータは結果リストの最初(つまり、最初の結果の前)にあります。すべての結果を順番に繰り返す方法は次のとおりです。
QFuture future ... QFutureIterator i(future) while (i.hasNext()) qDebug() << i.next()
next()関数は、futureから次の結果を返し(必要に応じて使用可能になるのを待ちます)、イテレーターをプッシュします。 STLスタイルのイテレータとは異なり、Javaスタイルのイテレータは結果を直接指すのではなく、結果を指します。 next()の最初の呼び出しは、イテレータを最初の結果と2番目の結果の間の位置に進め、最初の結果を返します。next()の2番目の呼び出しは、イテレータを2番目と3番目の結果の間に進め、2番目の結果を返します。など。
要素を逆の順序でトラバースする方法は次のとおりです。
QFutureIterator i(future) i.toBack() while (i.hasPrevious()) qDebug() << i.previous()
特定の値のすべてのオカレンスを検索する場合は、ループでfindNext()またはfindPrevious()を使用できます。
同じfutureで複数のイテレータを使用できます。QFutureIteratorがアクティブなときにfutureが変更された場合、QFutureIteratorは、変更されたコピーを無視して、元のfutureを繰り返し処理し続けます。
QFuture :: const_iterator
QFuture :: const_iteratorクラスは、QFutureにSTLスタイルの定数イテレーターを提供します。
デフォルトのQFuture :: const_iteratorコンストラクターは、初期化されていないイテレーターを作成します。反復を開始する前に、QFuture :: constBegin()やQFuture :: constEnd()などのQFuture関数を使用して反復を初期化する必要があります。
これは、すべてのQFuturesで利用可能な結果を出力する典型的なループです。
QFuture future = ... QFuture::const_iterator i for (i = future.constBegin() i != future.constEnd() ++i) cout << *i << endl