Sur cette page

Map et Map-Reduce simultanés

Les fonctions QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced() effectuent des calculs en parallèle sur les éléments d'une séquence, telle qu'une 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 framework.

Chacune des fonctions ci-dessus dispose d'une variante bloquante qui renvoie le résultat final au lieu d'une 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ésultat ci-dessus ne sont pas des objets ` QFuture `, mais des types de résultat réels (dans ce cas, ` QList<QImage>` et `QImage`).

Optimisation des inclusions

Si vous incluez l'en-tête <QtConcurrent>, l'intégralité du module Qt Concurrent ainsi que l'intégralité du module Qt Core seront incluses, 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>

Map concurrente

QtConcurrent::mapped() prend en paramètre une séquence d’entrée et une fonction de mappage. Cette fonction de mappage est ensuite appelée pour chaque élément de la séquence, et une nouvelle séquence contenant les valeurs renvoyées par la fonction de mappage est retournée.

La fonction de mappage doit se présenter sous la forme suivante :

U function(const T &t);

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

Cet exemple montre comment appliquer une fonction de mise à l'é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 transformation sont accessibles via QFuture. Consultez 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 se présenter sous la forme suivante :

U function(T &t);

Notez que la valeur de retour 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);

Comme la séquence est modifiée sur place, QtConcurrent::map() ne renvoie aucun résultat via QFuture. Vous pouvez toutefois utiliser QFuture et QFutureWatcher pour surveiller l'état de la fonction map.

Mappage concurrent et continuations

Le résultat de l'appel à QtConcurrent::mapped() est une QFuture contenant plusieurs résultats. Lorsque vous associez une continuation de type .then() à une telle QFuture, veillez à utiliser une continuation qui prend QFuture en 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 concurrent

QtConcurrent::mappedReduced() est similaire à QtConcurrent::mapped(), mais au lieu de renvoyer une séquence contenant les nouveaux résultats, ceux-ci sont combinés en une seule valeur à l'aide d'une fonction de réduction.

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

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

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

Appelez QtConcurrent::mappedReduced() comme suit :

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 `reduce` sera appelée une fois pour chaque résultat renvoyé par la fonction `map`, et doit fusionner le résultat intermédiaire dans la variable `result`. `QtConcurrent::mappedReduced()` garantit qu’un seul thread appellera `reduce` à la fois ; il n’est donc pas nécessaire d’utiliser un mutex pour verrouiller la variable `result`. L'énumération ` QtConcurrent::ReduceOptions ` permet de contrôler l'ordre dans lequel la réduction est effectuée. Si ` QtConcurrent::UnorderedReduce ` est utilisé (valeur 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 d'origine.

Fonctionnalités supplémentaires de l’API

Utilisation d’itérateurs à la place de `Sequence`

Chacune des fonctions ci-dessus dispose d'une variante qui prend une plage d'itérateurs à la place 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 bloquantes

Chacune des fonctions ci-dessus dispose d'une variante bloquante qui renvoie le résultat final au lieu d'une « 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ésultat ci-dessus ne sont pas des objets « QFuture », mais des types de résultat 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 :

// Comprimer toutes les chaînes de caractères d'une QStringList.
QStringList strings =...;
QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);

// Permuter les valeurs RVB 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 contenant les longueurs de toutes les chaînes d'une liste.
QStringList strings =...;
QFuture<QSet<int>> wordLengths = QtConcurrent::mappedReduced(strings, &QString::length,
                                                             qOverload<const int&>(&QSet<int>::insert));

Notez l'utilisation de ` qOverload`. Elle est nécessaire pour lever l'ambiguïté concernant les méthodes qui présentent plusieurs surcharges.

Notez également que lorsque vous utilisez `QtConcurrent::mappedReduced()`, vous pouvez combiner librement des fonctions normales et des fonctions membres :

// Il est possible de combiner 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 représentant la distribution des couleurs de toutes les images d'une liste.
extern int colorDistribution(const QImage &string);
QList<QImage> images =...;
QFuture<QSet<int>> distributionDeCouleursTotale = QtConcurrent::mappedReduced(images, colorDistribution,
                                                                        qOverload<const int&>(&QSet<int>::insert));

Utilisation des objets-fonctions

Les fonctions QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced() acceptent des objets fonction 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 fonctionnels 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 des expressions lambda

QtConcurrent::map(), QtConcurrent::mapped() et QtConcurrent::mappedReduced() acceptent des 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 combiner librement l'utilisation de fonctions normales, de fonctions membres et d'expressions lambda.

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 `reduce` :

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

Encapsulation de fonctions prenant plusieurs arguments

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

À titre d’exemple, nous allons utiliser 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ée directement avec QtConcurrent::mapped(), car cette dernière attend une fonction prenant 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.