Sur cette page

Map et Map-Reduce simultanés

Les fonctions QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced() exécutent des calculs en parallèle sur les éléments d'une séquence telle que QList. QtConcurrent::map() modifie une séquence sur place, QtConcurrent::mapped() renvoie une nouvelle séquence contenant le contenu modifié, et QtConcurrent::mappedReduced() renvoie un résultat unique.

Ces fonctions font partie du Qt Concurrent cadre.

Chacune des fonctions ci-dessus possède une variante bloquante qui renvoie le résultat final au lieu d'un QFuture. Vous les utilisez de la même manière que les variantes asynchrones.

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

Notez que les types de résultats ci-dessus ne sont pas des objets QFuture, mais des types de résultats réels (dans ce cas, QList<QImage> et QImage).

L'optimisation comprend

Si vous incluez l'en-tête <QtConcurrent>, tout le module Qt Concurrent et tout le module Qt Core seront inclus, ce qui peut augmenter les temps de compilation et la taille des binaires. Pour utiliser les fonctions QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced(), vous pouvez inclure un en-tête plus spécifique :

#include <QtConcurrentMap>

Concurrent Map

QtConcurrent::mapped() prend une séquence en entrée et une fonction map. Cette fonction est ensuite appelée pour chaque élément de la séquence, et une nouvelle séquence contenant les valeurs de retour de la fonction est renvoyée.

La fonction map doit être de la forme :

U function(const T &t);

T et U peuvent être de n'importe quel type (et même du même type), mais T doit correspondre au type stocké dans la séquence. La fonction renvoie le contenu modifié ou mappé.

Cet exemple montre comment appliquer une fonction d'échelle à tous les éléments d'une séquence :

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

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

Les résultats de la cartographie sont disponibles à l'adresse QFuture. Voir la documentation QFuture et QFutureWatcher pour plus d'informations sur l'utilisation de QFuture dans vos applications.

Si vous souhaitez modifier une séquence sur place, utilisez QtConcurrent::map(). La fonction map doit alors être de la forme :

U function(T &t);

Notez que la valeur et le type de retour de la fonction map ne sont pas utilisés.

L'utilisation de QtConcurrent::map() est similaire à celle de QtConcurrent::mapped() :

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

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

Puisque la séquence est modifiée sur place, QtConcurrent::map() ne renvoie aucun résultat via QFuture. Cependant, vous pouvez toujours utiliser QFuture et QFutureWatcher pour surveiller l'état de la carte.

Mappage concourant et continuités

Le résultat de l'appel à QtConcurrent::mapped() est un QFuture qui contient plusieurs résultats. Lorsque vous attachez une continuation .then() à un tel QFuture, assurez-vous d'utiliser une continuation qui prend QFuture comme paramètre, sinon seul le premier résultat sera traité :

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

Dans cet exemple, badFuture n'affichera qu'un seul résultat, tandis que goodFuture affichera tous les résultats.

Map-Reduce simultané

QtConcurrent::mappedReduced() est similaire à QtConcurrent::mapped(), mais au lieu de retourner une séquence avec les nouveaux résultats, les résultats sont combinés en une seule valeur en utilisant une fonction de réduction.

La fonction de réduction doit être de la forme :

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

T est le type du résultat final, U est le type de retour de la fonction map. Notez que la valeur et le type de retour de la fonction reduce ne sont pas utilisés.

Appelez QtConcurrent::mappedReduced() comme ceci :

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

La fonction de réduction sera appelée une fois pour chaque résultat renvoyé par la fonction map, et devrait fusionner les résultats intermédiaires dans la variable result. QtConcurrent::mappedReduced() garantit qu'un seul thread appellera reduce à la fois, donc l'utilisation d'un mutex pour verrouiller la variable résultat n'est pas nécessaire. L'enum QtConcurrent::ReduceOptions permet de contrôler l'ordre dans lequel la réduction est effectuée. Si QtConcurrent::UnorderedReduce est utilisé (par défaut), l'ordre est indéfini, tandis que QtConcurrent::OrderedReduce garantit que la réduction est effectuée dans l'ordre de la séquence originale.

Fonctionnalités supplémentaires de l'API

Utilisation d'itérateurs au lieu de séquences

Chacune des fonctions ci-dessus possède une variante qui prend une plage d'itérateurs au lieu d'une séquence. Vous les utilisez de la même manière que les variantes de séquence :

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

Variantes de blocage

Chacune des fonctions ci-dessus possède une variante bloquante qui renvoie le résultat final au lieu d'une adresse QFuture. Vous les utilisez de la même manière que les variantes asynchrones.

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

Notez que les types de résultats ci-dessus ne sont pas des objets QFuture, mais des types de résultats réels (dans ce cas, QList<QImage> et QImage).

Utilisation des fonctions membres

QtConcurrent::map(), QtConcurrent::mapped(), et QtConcurrent::mappedReduced() acceptent des pointeurs vers des fonctions membres. Le type de classe de la fonction membre doit correspondre au type stocké dans la séquence :

// Presser toutes les chaînes de caractères dans une QStringList.QStringList strings = ...;QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze) ;// Échange les valeurs rgb de tous les pixels d'une liste d'images.QList<QImage> images = ...;QFuture<QImage> bgrImages = QtConcurrent::mapped(images,static_cast<QImage(QImage::*)() const&>(&QImage::rgbSwapped)) ;// Créer un ensemble de longueurs pour toutes les chaînes de caractères d'une liste.QStringList strings = ...;QFuture<QSet<int>> wordLengths = QtConcurrent::mappedReduced(strings, &QString::longueur,                                                             qOverload<const int&>(&QSet<int>::insert));

Notez l'utilisation de qOverload, qui est nécessaire pour résoudre l'ambiguïté des méthodes qui ont plusieurs surcharges.

Notez également que lorsque vous utilisez QtConcurrent::mappedReduced(), vous pouvez mélanger librement l'utilisation des fonctions normales et des fonctions membres :

//  On peut mélanger des fonctions normales et des fonctions membres avec QtConcurrent::mappedReduced().// Calculer la longueur moyenne d'une liste de chaînes de caractères.extern void computeAverage(int &average, int length) ;QStringList strings = ...;QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage) ;// Créer un ensemble de distribution des couleurs de toutes les images d'une liste.extern int colorDistribution(const QImage &string) ;QList<QImage> images = ...;QFuture<QSet<int>> totalColorDistribution = QtConcurrent::mappedReduced(images, colorDistribution,                                                                        qOverload<const int&>(&QSet<int>::insert));

Utilisation d'objets de fonction

QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced() acceptent des objets fonctionnels pour la fonction map. Ces objets fonction peuvent être utilisés pour ajouter un état à un appel de fonction :

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

Les objets de fonction sont également pris en charge pour la fonction reduce :

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

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

Utilisation d'expressions lambda

QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced() acceptent les expressions lambda pour les fonctions map et reduce :

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

Lorsque vous utilisez QtConcurrent::mappedReduced() ou QtConcurrent::blockingMappedReduced(), vous pouvez mélanger l'utilisation de fonctions normales, de fonctions membres et d'expressions lambda librement.

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

Vous pouvez également passer une expression lambda en tant qu'objet de réduction :

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

Envelopper les fonctions qui prennent plusieurs arguments

Si vous souhaitez utiliser une fonction map qui prend plus d'un argument, vous pouvez utiliser une fonction lambda ou std::bind() pour la transformer en une fonction qui prend un seul argument.

À titre d'exemple, nous utiliserons QImage::scaledToWidth() :

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

scaledToWidth prend trois arguments (y compris le pointeur "this") et ne peut pas être utilisé avec QtConcurrent::mapped() directement, parce que QtConcurrent::mapped() attend une fonction qui prend un seul argument. Pour utiliser QImage::scaledToWidth() avec QtConcurrent::mapped(), nous devons fournir une valeur pour la largeur et le mode de transformation:

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.