Gleichzeitiges Map und Map-Reduce

Die Funktionen QtConcurrent::map(), QtConcurrent::mapped() und QtConcurrent::mappedReduced() führen parallel Berechnungen an den Elementen einer Sequenz, wie z.B. einer QList, durch. QtConcurrent::map() verändert eine Sequenz an Ort und Stelle, QtConcurrent::mapped() gibt eine neue Sequenz zurück, die den veränderten Inhalt enthält, und QtConcurrent::mappedReduced() gibt ein einzelnes Ergebnis zurück.

Diese Funktionen sind Teil des Qt Concurrent Frameworks.

Jede der oben genannten Funktionen hat eine blockierende Variante, die das Endergebnis anstelle von QFuture zurückgibt. Sie verwenden sie auf die gleiche Weise 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 die obigen Ergebnistypen keine QFuture Objekte sind, sondern echte Ergebnistypen (in diesem Fall QList<QImage> und QImage).

Gleichzeitige Karte

QtConcurrent::mapped() nimmt eine Eingabesequenz und eine Map-Funktion entgegen. Diese Map-Funktion wird dann für jedes Element in der Sequenz aufgerufen, und eine neue Sequenz mit den Rückgabewerten der Map-Funktion wird zurückgegeben.

Die Map-Funktion muss von der Form sein:

U function(const T &t);

T und U können von beliebigem Typ sein (und sie können sogar vom gleichen Typ sein), aber T muss mit dem in der Sequenz gespeicherten Typ übereinstimmen. Die Funktion gibt den geänderten oder gemappten Inhalt zurück.

In diesem Beispiel wird gezeigt, wie eine Skalierungsfunktion auf alle Elemente in 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 Abbildung werden über QFuture zur Verfügung gestellt. Weitere Informationen über die Verwendung von QFuture in Ihren Anwendungen finden Sie in der Dokumentation QFuture und QFutureWatcher.

Wenn Sie eine Sequenz an Ort und Stelle ändern wollen, verwenden Sie QtConcurrent::map(). Die map-Funktion muss dann von der Form sein:

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() ist ähnlich wie die 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 Abbildung zu überwachen.

Gleichzeitiges Map-Reduce

QtConcurrent::mappedReduced() ist ähnlich wie QtConcurrent::mapped(), aber anstatt eine Sequenz mit den neuen Ergebnissen zurückzugeben, werden die Ergebnisse mit Hilfe einer Reduktionsfunktion zu einem einzigen Wert kombiniert.

Die Reduktionsfunktion muss von der Form sein:

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 Reduzierfunktion 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 die Zwischenergebnisse in der Ergebnisvariablen zusammenführen. QtConcurrent::mappedReduced() garantiert, dass jeweils nur ein Thread reduce aufruft, so dass die Verwendung eines Mutex zum Sperren der Ergebnisvariablen nicht notwendig ist. Das QtConcurrent::ReduceOptions enum bietet eine Möglichkeit, die Reihenfolge der Reduktion zu kontrollieren. Wenn QtConcurrent::UnorderedReduce verwendet wird (die Voreinstellung), ist die Reihenfolge undefiniert, während QtConcurrent::OrderedReduce sicherstellt, dass die Reduktion in der Reihenfolge der ursprünglichen Sequenz durchgeführt wird.

Zusätzliche API-Funktionen

Verwendung von Iteratoren anstelle von Sequenzen

Jede der oben genannten Funktionen hat eine Variante, die einen Iteratorbereich anstelle einer Sequenz annimmt. Sie verwenden sie auf die gleiche Weise 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);

Blockierungs-Varianten

Für jede der oben genannten Funktionen gibt es eine blockierende Variante, die anstelle von QFuture das Endergebnis zurückliefert. Sie werden wie die asynchronen Varianten verwendet.

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 die obigen Ergebnistypen keine QFuture Objekte sind, sondern echte Ergebnistypen (in diesem Fall QList<QImage> und QImage).

Verwendung von Memberfunktionen

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 Strings in eine QStringList quetschen.QStringList strings = ...;QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);// Tausche 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));// Erstellen einer Menge der Längen aller Strings 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. Sie wird benötigt, um die Mehrdeutigkeit für die Methoden zu lösen, die mehrere Überladungen haben.

Beachten Sie auch, dass Sie bei der Verwendung von QtConcurrent::mappedReduced() die Verwendung von normalen und Mitgliedsfunktionen frei mischen können:

// Kann normale Funktionen und Memberfunktionen mit QtConcurrent::mappedReduced() mischen.// Berechne die durchschnittliche Länge einer Liste von Strings.extern void computeAverage(int &average, int length);QStringList strings = ...;QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage);// Erstellen einer Menge der Farbverteilung aller Bilder in einer Liste.extern int colorDistribution(const QImage &string);QList<QImage> images = ...;QFuture<QSet<int>> totalColorDistribution = 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);

Lambda-Ausdrücke verwenden

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();

Wenn Sie QtConcurrent::mappedReduced() oder QtConcurrent::blockingMappedReduced() verwenden, können Sie die Verwendung von normalen Funktionen, Mitgliedsfunktionen und Lambda-Ausdrücken frei mischen.

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();

Wrapping von Funktionen, die mehrere Argumente annehmen

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

Als Beispiel verwenden wir QImage::scaledToWidth():

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

scaledToWidth benötigt drei Argumente (einschließlich des "this"-Zeigers) und kann nicht direkt mit QtConcurrent::mapped() verwendet werden, da QtConcurrent::mapped() eine Funktion erwartet, die ein Argument benötigt. 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);

© 2025 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.