En esta página

Map y Map-Reduce concurrentes

Las funciones QtConcurrent::map(), QtConcurrent::mapped() y QtConcurrent::mappedReduced() ejecutan cálculos en paralelo sobre los elementos de una secuencia como QList. QtConcurrent::map() modifica una secuencia in situ, QtConcurrent::mapped() devuelve una nueva secuencia con el contenido modificado, y QtConcurrent::mappedReduced() devuelve un único resultado.

Estas funciones forman parte del Qt Concurrent framework.

Cada una de las funciones anteriores tiene una variante de bloqueo que devuelve el resultado final en lugar de un QFuture. Se utilizan del mismo modo que las variantes asíncronas.

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

Nótese que los tipos de resultado anteriores no son objetos QFuture, sino tipos de resultado reales (en este caso, QList<QImage> y QImage).

Optimizar incluye

Si incluye la cabecera <QtConcurrent>, se incluirá todo el módulo Qt Concurrent con todo el módulo Qt Core, lo que puede aumentar los tiempos de compilación y el tamaño de los binarios. Para utilizar las funciones QtConcurrent::map(), QtConcurrent::mapped(), y QtConcurrent::mappedReduced(), puede incluir una cabecera más específica:

#include <QtConcurrentMap>

Mapa concurrente

QtConcurrent::mapped() toma una secuencia de entrada y una función map. Esta función map se llama para cada elemento de la secuencia, y se devuelve una nueva secuencia que contiene los valores de retorno de la función map.

La función map debe tener la forma

U function(const T &t);

T y U pueden ser de cualquier tipo (e incluso pueden ser del mismo tipo), pero T debe coincidir con el tipo almacenado en la secuencia. La función devuelve el contenido modificado o mapeado.

Este ejemplo muestra cómo aplicar una función de escala a todos los elementos de una secuencia:

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

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

Los resultados del mapa están disponibles a través de QFuture. Consulte la documentación de QFuture y QFutureWatcher para obtener más información sobre cómo utilizar QFuture en sus aplicaciones.

Si desea modificar una secuencia in situ, utilice QtConcurrent::map(). La función map debe ser entonces de la forma

U function(T &t);

Tenga en cuenta que el valor de retorno y el tipo de retorno de la función map no se utilizan.

Usar QtConcurrent::map() es similar a usar QtConcurrent::mapped():

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

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

Dado que la secuencia se modifica in situ, QtConcurrent::map() no devuelve ningún resultado a través de QFuture. Sin embargo, puede seguir utilizando QFuture y QFutureWatcher para controlar el estado del mapa.

Mapas concurrentes y continuaciones

El resultado de la llamada a QtConcurrent::mapped() es un QFuture que contiene múltiples resultados. Cuando adjunte una continuación .then() a dicho QFuture, asegúrese de utilizar una continuación que tome QFuture como parámetro, de lo contrario sólo se procesará el primer resultado:

auto proceso = [](int val) { return val * 2; };QList<int> inputs { 1, 2, 3 };auto badFuture = QtConcurrent::mapped(inputs, process) . then([](int val) {                             qDebug() << val;
                         });auto buenFuturo = QtConcurrent::mapped(inputs, process) .then([](QFuture<int> f) { for(auto r : f.results()) {                                  qDebug() << r;
                              } });

En este ejemplo badFuture sólo imprimirá un único resultado, mientras que goodFuture imprimirá todos los resultados.

Map-Reduce concurrente

QtConcurrent::mappedReduced() es similar a QtConcurrent::mapped(), pero en lugar de devolver una secuencia con los nuevos resultados, los resultados se combinan en un único valor usando una función de reducción.

La función de reducción debe ser de la forma

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

T es el tipo del resultado final, U es el tipo de retorno de la función map. Tenga en cuenta que el valor de retorno y el tipo de retorno de la función de reducción no se utilizan.

Llama a QtConcurrent::mappedReduced() así:

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 función reducir se llamará una vez por cada resultado devuelto por la función map, y deberá fusionar el intermedio en la variable resultado. QtConcurrent::mappedReduced() garantiza que sólo un hilo llamará a reduce a la vez, por lo que no es necesario usar un mutex para bloquear la variable resultado. El enum QtConcurrent::ReduceOptions proporciona una forma de controlar el orden en el que se realiza la reducción. Si se utiliza QtConcurrent::UnorderedReduce (por defecto), el orden es indefinido, mientras que QtConcurrent::OrderedReduce garantiza que la reducción se realiza en el orden de la secuencia original.

Características adicionales de la API

Uso de iteradores en lugar de secuencias

Cada una de las funciones anteriores tiene una variante que toma un rango de iteradores en lugar de una secuencia. Se utilizan del mismo modo que las variantes de secuencia:

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 bloqueo

Cada una de las funciones anteriores tiene una variante de bloqueo que devuelve el resultado final en lugar de QFuture. Se utilizan del mismo modo que las variantes asíncronas.

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

Tenga en cuenta que los tipos de resultado anteriores no son objetos QFuture, sino tipos de resultado reales (en este caso, QList<QImage> y QImage).

Uso de funciones miembro

QtConcurrent::map(), QtConcurrent::mapped() y QtConcurrent::mappedReduced() aceptan punteros a funciones miembro. El tipo de clase de la función miembro debe coincidir con el tipo almacenado en la secuencia:

// Exprimir todas las cadenas en una QStringList.QStringList strings = ...;QFuture<void> cadenasexprimidas = QtConcurrent::map(cadenas, &QString::squeeze);// Intercambia los valores rgb de todos los píxeles de una lista de imágenes.QList<QImage> images = ...;QFuture<QImage> bgrImages = QtConcurrent::mapped(images,static_cast<QImage(QImage::*)() const&>(&QImage::rgbSwapped));// Crear un conjunto de las longitudes de todas las cadenas de una lista.QStringList cadenas = ...;QFuture<QSet<int><> wordLengths = QtConcurrent::mappedReduced(cadenas, &QString::longitud,                                                             qOverload<const int&>(&QSet<int>::insert));

Nótese el uso de qOverload. Es necesario para resolver la ambigüedad de los métodos, que tienen múltiples sobrecargas.

También tenga en cuenta que cuando se utiliza QtConcurrent::mappedReduced(), puede mezclar el uso de funciones normales y funciones miembro libremente:

// Puede mezclar funciones normales y funciones miembro con QtConcurrent::mappedReduced().// Calcular la longitud media de una lista de cadenas.extern void computeAverage(int &average, int length);QStringList cadenas = ...;QFuture<int> longitudPromedio = QtConcurrent::mappedReduced(cadenas, &QString::length, computeAverage);// Crear un conjunto de ladistribución del color de todas las imágenes de una lista.extern int colorDistribution(const QImage &string);QList<QImage> images = ...;QFuture<QSet<int><> totalDistribuciónColor = QtConcurrent::mappedReduced(imágenes, distribuciónColor,                                                                        qOverload<const int&>(&QSet<int>::insert));

Uso de objetos de función

QtConcurrent::map(), QtConcurrent::mapped(), y QtConcurrent::mappedReduced() aceptan objetos de función para la función map. Estos objetos de función se pueden utilizar para añadir estado a una llamada de función:

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

También se admiten objetos de función para la función reduce:

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

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

Uso de expresiones lambda

QtConcurrent::map(), QtConcurrent::mapped() y QtConcurrent::mappedReduced() aceptan expresiones lambda para las funciones map y 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();

Al usar QtConcurrent::mappedReduced() o QtConcurrent::blockingMappedReduced(), puede mezclar libremente el uso de funciones normales, funciones miembro y expresiones lambda.

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

También puede pasar una lambda como objeto 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();

Envolver funciones que toman múltiples argumentos

Si quieres utilizar una función map que toma más de un argumento puedes utilizar una función lambda o std::bind() para transformarla en una función que toma un argumento.

Como ejemplo, usaremos QImage::scaledToWidth():

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

scaledToWidth toma tres argumentos (incluyendo el puntero "this") y no puede usarse con QtConcurrent::mapped() directamente, porque QtConcurrent::mapped() espera una función que tome un argumento. Para usar QImage::scaledToWidth() con QtConcurrent::mapped() tenemos que proporcionar un valor para la anchura y el modo de transformación:

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.