Auf dieser Seite

Paralleles Map und Map-Reduce

Die Funktionen QtConcurrent::map(), QtConcurrent::mapped() und QtConcurrent::mappedReduced() führen Berechnungen parallel auf den Elementen einer Sequenz durch, beispielsweise einer ` QList`. QtConcurrent::map() ändert eine Sequenz direkt an Ort und Stelle, QtConcurrent::mapped() gibt eine neue Sequenz mit dem geänderten Inhalt zurück und QtConcurrent::mappedReduced() gibt ein einzelnes Ergebnis zurück.

Diese Funktionen sind Teil des Qt Concurrent Frameworks.

Jede der oben genannten Funktionen verfügt über eine blockierende Variante, die anstelle eines „ QFuture “ das Endergebnis zurückgibt. Sie werden auf dieselbe Weise verwendet wie die asynchronen Varianten.

QList<QImage> images = ...;

// Each call blocks until the entire operation is finished.
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);

QtConcurrent::blockingMap(images, scale);

QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

Beachten Sie, dass es sich bei den oben genannten Ergebnistypen nicht um „ QFuture “-Objekte handelt, sondern um echte Ergebnistypen (in diesem Fall „ QList<QImage>“ und „QImage“).

Includes optimieren

Wenn Sie den Header „ <QtConcurrent> “ einbinden, werden das gesamte Modul „ Qt Concurrent “ sowie das gesamte Modul „ Qt Core “ eingebunden, was zu längeren Kompilierungszeiten und größeren Binärdateien führen kann. Um die Funktionen „ QtConcurrent::map()“, „ QtConcurrent::mapped()“ und „ QtConcurrent::mappedReduced()“ zu verwenden, können Sie einen spezifischeren Header einbinden:

#include <QtConcurrentMap>

Concurrent Map

QtConcurrent::mapped() nimmt eine Eingabesequenz und eine Map-Funktion entgegen. Diese Map-Funktion wird dann für jedes Element der Sequenz aufgerufen, und es wird eine neue Sequenz zurückgegeben, die die Rückgabewerte der Map-Funktion enthält.

Die Map-Funktion muss folgende Form haben:

U function(const T &t);

T und U können beliebige Typen sein (und sogar denselben Typ haben), aber T muss mit dem in der Sequenz gespeicherten Typ übereinstimmen. Die Funktion gibt den modifizierten oder abgebildeten Inhalt zurück.

Dieses Beispiel zeigt, wie eine Skalierungsfunktion auf alle Elemente einer Sequenz angewendet wird:

QImage scaled(const QImage &image)
{
    return image.scaled(100, 100);
}

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);

Die Ergebnisse der Zuordnung werden über ` QFuture` bereitgestellt. Weitere Informationen zur Verwendung von ` QFuture ` in Ihren Anwendungen finden Sie in der Dokumentation unter QFuture und QFutureWatcher.

Wenn Sie eine Sequenz an Ort und Stelle ändern möchten, verwenden Sie QtConcurrent::map(). Die Map-Funktion muss dann folgende Form haben:

U function(T &t);

Beachten Sie, dass der Rückgabewert und der Rückgabetyp der `map`-Funktion nicht verwendet werden.

Die Verwendung von `QtConcurrent::map()` ähnelt der Verwendung von `QtConcurrent::mapped()`:

void scale(QImage &image)
{
    image = image.scaled(100, 100);
}

QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);

Da die Sequenz an Ort und Stelle verändert wird, gibt QtConcurrent::map() keine Ergebnisse über ` QFuture` zurück. Sie können jedoch weiterhin ` QFuture ` und ` QFutureWatcher ` verwenden, um den Status der Map-Funktion zu überwachen.

Parallele Zuordnungen und Fortsetzungen

Das Ergebnis eines Aufrufs von `QtConcurrent::mapped()` ist ein ` QFuture `, das mehrere Ergebnisse enthält. Wenn Sie eine ` .then() `-Fortsetzung an ein solches ` QFuture` anhängen, achten Sie darauf, eine Fortsetzung zu verwenden, die ` QFuture ` als Parameter übernimmt; andernfalls wird nur das erste Ergebnis verarbeitet:

auto process = [](int val) {
    return val * 2;
};

QList<int> inputs { 1, 2, 3 };
auto badFuture = QtConcurrent::mapped(inputs, process)
                         .then([](int val) {
                             qDebug() << val;
                         });

auto goodFuture = QtConcurrent::mapped(inputs, process)
                          .then([](QFuture<int> f) {
                              for (auto r : f.results()) {
                                  qDebug() << r;
                              }
                          });

In diesem Beispiel gibt „ badFuture “ nur ein einziges Ergebnis aus, während „ goodFuture “ alle Ergebnisse ausgibt.

Paralleles Map-Reduce

`QtConcurrent::mappedReduced()` ähnelt `QtConcurrent::mapped()`, gibt jedoch keine Sequenz mit den neuen Ergebnissen zurück, sondern fasst die Ergebnisse mithilfe einer Reduce-Funktion zu einem einzigen Wert zusammen.

Die Reduce-Funktion muss folgende Form haben:

V function(T &result, const U &intermediate)

T ist der Typ des Endergebnisses, U ist der Rückgabetyp der Map-Funktion. Beachten Sie, dass der Rückgabewert und der Rückgabetyp der Reduce-Funktion nicht verwendet werden.

Rufen Sie `QtConcurrent::mappedReduced()` wie folgt auf:

void addToCollage(QImage &collage, const QImage &thumbnail)
{
    QPainter p(&collage);
    static QPoint offset = QPoint(0, 0);
    p.drawImage(offset, thumbnail);
    offset += ...;
}

QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);

Die `reduce`-Funktion wird für jedes von der `map`-Funktion zurückgegebene Ergebnis einmal aufgerufen und sollte den Zwischenspeicher in die Ergebnisvariable zusammenführen. `QtConcurrent::mappedReduced()` garantiert, dass jeweils nur ein Thread die `reduce`-Funktion aufruft, sodass die Verwendung eines Mutex zur Sperrung der Ergebnisvariable nicht erforderlich ist. Die Enumeration „ QtConcurrent::ReduceOptions “ bietet eine Möglichkeit, die Reihenfolge zu steuern, in der die Reduktion durchgeführt wird. Bei Verwendung von „ QtConcurrent::UnorderedReduce “ (Standard) ist die Reihenfolge undefiniert, während „ QtConcurrent::OrderedReduce “ sicherstellt, dass die Reduktion in der Reihenfolge der ursprünglichen Sequenz erfolgt.

Weitere API-Funktionen

Verwendung von Iteratoren anstelle von Sequenzen

Jede der oben genannten Funktionen verfügt über eine Variante, die anstelle einer Sequenz einen Iteratorbereich akzeptiert. Sie werden genauso verwendet wie die Sequenzvarianten:

QList<QImage> images = ...;

QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);

// Map in-place only works on non-const iterators.
QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);

QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);

Blockierende Varianten

Jede der oben genannten Funktionen verfügt über eine blockierende Variante, die anstelle eines „ QFuture “ das Endergebnis zurückgibt. Sie werden genauso verwendet wie die asynchronen Varianten.

QList<QImage> images = ...;

// Each call blocks until the entire operation is finished.
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);

QtConcurrent::blockingMap(images, scale);

QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

Beachten Sie, dass es sich bei den oben genannten Ergebnistypen nicht um „ QFuture “-Objekte handelt, sondern um echte Ergebnistypen (in diesem Fall „ QList<QImage>“ und „QImage“).

Verwendung von Mitgliedsfunktionen

QtConcurrent::map(), QtConcurrent::mapped() und QtConcurrent::mappedReduced() akzeptieren Zeiger auf Mitgliedsfunktionen. Der Klassentyp der Mitgliedsfunktion muss mit dem in der Sequenz gespeicherten Typ übereinstimmen:

// Alle Zeichenketten in einer QStringList komprimieren.
QStringList strings =...;
QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);

// Vertausche die RGB-Werte aller Pixel in einer Liste von Bildern.
QList<QImage> images =...;
QFuture<QImage> bgrImages = QtConcurrent::mapped(images,
    static_cast<QImage (QImage::*)() const &>(&QImage::rgbSwapped));

// Erzeuge eine Menge aus den Längen aller Zeichenfolgen in einer Liste.
QStringList strings =...;
QFuture<QSet<int>> wordLengths = QtConcurrent::mappedReduced(strings, &QString::length,
                                                             qOverload<const int&>(&QSet<int>::insert));

Beachten Sie die Verwendung von „ qOverload “. Dies ist erforderlich, um die Mehrdeutigkeit bei Methoden zu beseitigen, die über mehrere Überladungen verfügen.

Beachten Sie außerdem, dass Sie bei der Verwendung von `QtConcurrent::mappedReduced()` normale Funktionen und Member-Funktionen beliebig miteinander kombinieren können:

// Mit QtConcurrent::mappedReduced() können normale Funktionen und Member-Funktionen gemischt werden.

// Berechne die durchschnittliche Länge einer Liste von Zeichenketten.
extern void computeAverage(int &average, int length);
QStringList strings =...;
QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage);

// Erstellen Sie eine Menge der Farbverteilung aller Bilder in einer Liste.
extern int colorDistribution(const QImage &string);
QList<QImage> images =...;
QFuture<QSet<int>> Gesamtfarbverteilung = QtConcurrent::mappedReduced(images, colorDistribution,
                                                                        qOverload<const int&>(&QSet<int>::insert));

Verwendung von Funktionsobjekten

QtConcurrent::map(), QtConcurrent::mapped() und QtConcurrent::mappedReduced() akzeptieren Funktionsobjekte für die Map-Funktion. Diese Funktionsobjekte können verwendet werden, um einem Funktionsaufruf einen Zustand hinzuzufügen:

struct Scaled
{
    Scaled(int size)
    : m_size(size) { }

    typedef QImage result_type;

    QImage operator()(const QImage &image)
    {
        return image.scaled(m_size, m_size);
    }

    int m_size;
};

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));

Funktionsobjekte werden auch für die „reduce“-Funktion unterstützt:

struct ImageTransform
{
    void operator()(QImage &result, const QImage &value);
};

QFuture<QImage> thumbNails =
        QtConcurrent::mappedReduced(images, Scaled(100), ImageTransform(),
                                    QtConcurrent::SequentialReduce);

Verwendung von Lambda-Ausdrücken

QtConcurrent::map(), QtConcurrent::mapped() und QtConcurrent::mappedReduced() akzeptieren Lambda-Ausdrücke für die Map- und Reduce-Funktion:

QList<int> vector { 1, 2, 3, 4 };
QtConcurrent::blockingMap(vector, [](int &x) { x *= 2; });

int size = 100;
QList<QImage> images = ...;

QList<QImage> thumbnails = QtConcurrent::mapped(images,
        [&size](const QImage &image) {
            return image.scaled(size, size);
        }
    ).results();

Bei der Verwendung von QtConcurrent::mappedReduced() oder QtConcurrent::blockingMappedReduced() können Sie normale Funktionen, Member-Funktionen und Lambda-Ausdrücke beliebig miteinander kombinieren.

QList<QImage> collage = QtConcurrent::mappedReduced(images,
        [&size](const QImage &image) {
            return image.scaled(size, size);
        },
        addToCollage
   ).results();

Sie können auch ein Lambda als „reduce“-Objekt übergeben:

QList<QImage> collage = QtConcurrent::mappedReduced(images,
        [&size](const QImage &image) {
            return image.scaled(size, size);
        },
        [](QImage &result, const QImage &value) {
            // do some transformation
        }
   ).results();

Funktionen mit mehreren Argumenten verpacken

Wenn Sie eine Map-Funktion verwenden möchten, die mehr als ein Argument entgegennimmt, können Sie eine Lambda-Funktion oder ` std::bind() ` nutzen, um sie in eine Funktion umzuwandeln, die ein Argument entgegennimmt.

Als Beispiel verwenden wir `QImage::scaledToWidth()`:

QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;

scaledToWidth nimmt drei Argumente entgegen (einschließlich des „this“-Zeigers) und kann nicht direkt mit QtConcurrent::mapped() verwendet werden, da QtConcurrent::mapped() eine Funktion erwartet, die ein Argument entgegennimmt. Um `QImage::scaledToWidth()` mit `QtConcurrent::mapped()` zu verwenden, müssen wir einen Wert für die Breite und den Transformationsmodus angeben:

QList<QImage> images = ...;
std::function<QImage(const QImage &)> scale = [](const QImage &img) {
    return img.scaledToWidth(100, Qt::SmoothTransformation);
};
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scale);

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.