1

这是我第一次尝试使用 QtConcurrent::blockingMappedReduced,但我无法在 MSVC 2010 Express 中构建它(使用 QT 4.7.1 源代码)。

我创建了一个与我的实际代码相似的小示例,并且构建时存在相同的问题:

// Here's the general outline:
// 1. create a list of random numbers
// 2. pass the list to blockingMappedReduced
// 3. the map function calculates the sine of the given random number
// 4. the reduce function finds the random number with the maximum sine value

// Here's the implementation:

#include "stdafx.h"
#include <qlist.h>
#include <qtconcurrentmap.h>

// My class for the map/reduce functions
class myClass
{
private:

    // Nested class to hold the intermediate results from the map function
    // I think I need this because the reduce function needs more from the map function than a single return value
    class Temp
    {
    public:

        // For example, let's pass these two member variables from the map function to the reduce function
        int randomInput;
        double resultingOutput;

        // The Temp constructor
        Temp::Temp(double randomInput, double resultingOutput)
        {
            this->randomInput = randomInput;
            this->resultingOutput = resultingOutput;
        }
    };

public:

    // For example, these myClass members will hold the final result from the reduce function
    double maximumOutput;
    double maximumInput;

    // The myClass constructor
    myClass::myClass()
    {
        this->maximumOutput = -1;
    }

    // The map function
    const Temp mapFunction(const double& randomInput)
    {
        // For example, let's calculate the sine of the given random number
        double resultingOutput = sin(randomInput);

        // Construct the temporary structure to pass multiple values to the reduce function
        const Temp temp(randomInput, resultingOutput);
        return(temp);
    }

    // The reduce function
    void reduceFunction(double& maxInput, const Temp& temp)
    {
        // For example, let's find the maximum computed sine value
        if (temp.resultingOutput > this->maximumOutput)
        {
            this->maximumOutput = temp.resultingOutput;
            this->maximumInput = temp.randomInput;
        }

        maxInput = this->maximumInput;
    }
};

// Main function
void main(int argc, _TCHAR* argv[])
{
    // Build a list of random numbers
    QList<int> aList;
    for (int count = 8; count > 0; --count)
    {
        aList.append(rand());
    }

    // Invoke the parallel map/reduce function
    myClass myClassInstance;
    double theAnswer = QtConcurrent::blockingMappedReduced(aList, &myClass::mapFunction, &myClass::reduceFunction);
}

编译器抱怨最后一行调用了blockingMappedReduced。

c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'D QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__thiscall C::* )(void) const,U (__thiscall D::* )(V),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(659) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'C QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__cdecl *)(U),V (__thiscall C::* )(W),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(643) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'V QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__thiscall C::* )(void) const,U (__cdecl *)(V &,W),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(627) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'W QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__cdecl *)(U),V (__cdecl *)(W &,X),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(611) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'ResultType QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__thiscall C::* )(void) const,ReduceFunctor,QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(595) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'ResultType QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__cdecl *)(U),ReduceFunctor,QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(579) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'C QtConcurrent::blockingMappedReduced(Iterator,Iterator,MapFunctor,T (__thiscall C::* )(U),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(563) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'U QtConcurrent::blockingMappedReduced(Iterator,Iterator,MapFunctor,T (__cdecl *)(U &,V),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(547) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'ResultType QtConcurrent::blockingMappedReduced(Iterator,Iterator,MapFunctor,ReduceFunctor,QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(536) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'D QtConcurrent::blockingMappedReduced(const Sequence &,T (__thiscall C::* )(void) const,U (__thiscall D::* )(V),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(void) const' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(522) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'C QtConcurrent::blockingMappedReduced(const Sequence &,T (__cdecl *)(U),V (__thiscall C::* )(W),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U)' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(508) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'V QtConcurrent::blockingMappedReduced(const Sequence &,T (__thiscall C::* )(void) const,U (__cdecl *)(V &,W),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(void) const' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(494) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'W QtConcurrent::blockingMappedReduced(const Sequence &,T (__cdecl *)(U),V (__cdecl *)(W &,X),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U)' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(480) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'ResultType QtConcurrent::blockingMappedReduced(const Sequence &,T (__thiscall C::* )(void) const,ReduceFunctor,QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(void) const' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(466) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'ResultType QtConcurrent::blockingMappedReduced(const Sequence &,T (__cdecl *)(U),ReduceFunctor,QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U)' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(452) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'C QtConcurrent::blockingMappedReduced(const Sequence &,MapFunctor,T (__thiscall C::* )(U),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(U)' from 'void (__thiscall myClass::* )(double &,const myClass::Temp &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(438) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'U QtConcurrent::blockingMappedReduced(const Sequence &,MapFunctor,T (__cdecl *)(U &,V),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U &,V)' from 'void (__thiscall myClass::* )(double &,const myClass::Temp &)'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(424) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2783: 'ResultType QtConcurrent::blockingMappedReduced(const Sequence &,MapFunctor,ReduceFunctor,QtConcurrent::ReduceOptions)' : could not deduce template argument for 'ResultType'
          c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(414) : see declaration of 'QtConcurrent::blockingMappedReduced'

来自在线 QT 文档(http://doc.qt.nokia.com/4.7-snapshot/qtconcurrentmap.html#blockingMappedReduced),原型如下:

T  blockingMappedReduced ( const Sequence & sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce ) 

恐怕我没有调试这个的专业知识。任何帮助将不胜感激。同样,由于我的 C++ 技能不是专家,因此需要明确的帮助才能让我理解它(即实际的代码片段,而不是假定比我拥有更多知识的东西,例如“你的论点必须是一个恒定的参考” )。

在此先感谢您的帮助。

4

2 回答 2

2

HostileFork:再次感谢您的帮助。你让我回到了让我真正的代码工作的轨道上。

只是为了完整起见,这是我的原始示例,其中包含使 blockingMappedReduced 工作所需的最小更改(但仍然存在我混乱的 C++ 样式问题)。这就是我如何通过您的解决方案来了解什么是什么。它可能会帮助其他人理清哪些是 blockingMappedReduced 问题,哪些是 C++ 问题:

#include "stdafx.h"
#include <qlist.h>
#include <qtconcurrentmap.h>


// My class for the map/reduce functions
class myClass
{
    // Nested class to hold the intermediate results from the map function
    // I think I need this because the reduce function needs more from the map function than a single return value
    class Temp
    {
    public:

        // For example, let's pass these two member variables from the map function to the reduce function
        int randomInput;
        double resultingOutput;

        // default Temp constructor
        Temp()
        {
        };

        // The Temp constructor
        Temp(double randomInput, double resultingOutput)
        {
            this->randomInput = randomInput;
            this->resultingOutput = resultingOutput;
        }
    };

public:

    // For example, these myClass members will hold the final result from the reduce function
    double maximumOutput;
    double maximumInput;

    // The myClass constructor
    myClass()
    {
        this->maximumOutput = -1;
    }

    // The map function
    static Temp myClass::mapFunction(const int& randomInput)
    {
        // For example, let's calculate the sine of the given random number
        double resultingOutput = sin((double)randomInput);

        // Construct the temporary structure to pass multiple values to the reduce function
        Temp temp(randomInput, resultingOutput);
        return(temp);
    }

    // The reduce function
    static void myClass::reduceFunction(myClass& accumulator, const Temp& temp)
    {
        // For example, let's find the maximum computed sine value
        if (temp.resultingOutput > accumulator.maximumOutput)
        {
            accumulator.maximumOutput = temp.resultingOutput;
            accumulator.maximumInput = temp.randomInput;
        }
    }
};


// Main function
int main(int argc, _TCHAR* argv[])
{
    // Build a list of random numbers
    QList<int> aList;
    for (int count = 8; count > 0; --count)
    {
        aList.append(rand());
    }

    // Invoke the parallel map/reduce function
    myClass theAnswer = QtConcurrent::blockingMappedReduced(aList, &myClass::mapFunction, &myClass::reduceFunction);

    return(0);
}
于 2011-11-01T08:07:15.133 回答
2

您的代码有一些与 QtConcurrent 无关的一般问题需要修补。首先,你不应该限定构造函数,所以而不是:

    // The Temp constructor
    Temp::Temp(double randomInput, double resultingOutput)

你应该简单地写:

    // The Temp constructor
    Temp(double randomInput, double resultingOutput)

myClass. 此外,您的 main 函数签名应始终返回一个,int尽管在 C99 和 C++ 中,如果您想返回 0,您可以省略 return 语句。(但是,我总是return 0根据个人喜好明确放置。)

main() 在 C 和 C++ 中应该返回什么?

至于您的 QtConcurrent 问题,有几个。首先,您的 QList 是整数,并且文档指出序列中的类型应匹配 map 函数的第一个参数(您有一个双精度参数)。因此,QList 需要更改为 double - 或者 - 您的 map 函数需要采用 int。

您遇到的另一个问题是您试图将指向成员函数的指针传递到只需要普通函数的插槽中:

    // Invoke the parallel map/reduce function
    myClass myClassInstance;
    double theAnswer = QtConcurrent::blockingMappedReduced(aList,
        &myClass::mapFunction, &myClass::reduceFunction);

myClassInstance请注意,除了声明之外没有提及。在一般情况下......解决这个问题并不像更改对使用的调用那么容易&myClassInstance::mapFunction, &myClassInstance::reduceFunction。当您环顾 C++ 时,您会发现通常没有可行的方法来制作可以放入函数调用的任何插槽中的对象,即使它们被设计为看起来像函数一样可调用:

帮助提升绑定/功能

幸运的是,QtConcurrent 并没有让你陷入困境。它预测了对函数对象的需求:

http://doc.qt.io/archives/qt-4.7/qtconcurrentmap.html#using-function-objects

但是,与其深入研究如何使其工作,我们应该首先考虑为什么要将这些作为成员函数。Map/Reduce 模型允许您定义自定义累加器和结果类型,这可以让您轻松获得所需的内容。这是一个更简单的版本,希望能够编译并让您更接近:

#include <qlist.h>
#include <qtconcurrentmap.h>

#include <cmath> // for sin()
#include <algorithm> // for min, max, etc.
#include <limits> // for numeric_limits

struct MapResult // same as class, but "public" by default
{
    double input;
    double output;

    // must be "default constructible" due to guts of QtConcurrent :-/    
    // implementation artifact, don't worry about it affecting you...
    MapResult () {}

    MapResult (double input, double output) :
        // initializing members like this is cleaner than this->x = x...
        // and for certain members you HAVE to do it this way
        input (input), output (output)
    {
    }
};

struct ReduceAccumulator // same as class, but "public" by default
{
    MapResult largest;

    ReduceAccumulator () :
        // a better choice than 0 for an "uninitialized max" since
        // any other double will be larger...but you really should
        // probably accomodate a "no entries" case
        largest (MapResult (0, std::numeric_limits<double>::min())
    {
    }
};

// pattern of return type should be "U", not "const U" according to docs
MapResult mapFunction(const double& input) 
{
    // no need to construct a named local var if you don't want to
    // also no parentheses needed on return(x); ... return x; is fine 
    return MapResult (input, sin(input));
}

void reduceFunction(ReduceAccumulator& acc, const MapResult& oneResult)
{
    if (oneResult.output > acc.largest.output) {
        acc.largest = oneResult
    }
}

int main(int argc, char* argv[])
{
    QList<double> aList;
    for (int count = 8; count > 0; --count)
    {
        aList.append(rand());
    }

    ReduceAccumulator answer = QtConcurrent::blockingMappedReduced(
        aList, &mapFunction, &reduceFunction);

    return 0;
}

包括一些通用的 C++ 注释,希望对您有所帮助...


更新:他们提供的另一条路线确实使用了成员函数,但它对您尝试编写的样式做出了一些不同的假设。首先,它假设您的序列输入类型是一个类(double是“POD”或“plain-old-data”类型并且没有方法分派)。那么参数是隐式的。

但请注意,如果您想使用这种技术,它会以特定方式对代码进行样式化。以下是更改:

struct ReduceAccumulator
{
    MapResult largest;

    ReduceAccumulator () :
        largest (MapResult(0, std::numeric_limits<double>::min())
    {
    }

    // runs on non-const object, and drops first parameter (now implicit)
    void reduceFunction(const MapResult& oneResult)
    {
        if (oneResult.output > largest.output) {
            largest = oneResult
        }
    }
};

struct MyDouble {
    double d;

    MyDouble (double d) : d (d) {}

    // as member it takes no arguments, and needs to run on const objects
    MapResult mapFunction() const 
    {
        return MapResult (d, sin(d));
    }
};

int main(int argc, char* argv[])
{
    // to use a member as mapFunction, must be a member of input sequence type
    QList<MyDouble> aList;
    for (int count = 8; count > 0; --count)
    {
        aList.append(MyDouble (rand()));
    }

    ReduceAccumulator theAnswer = QtConcurrent::blockingMappedReduced(
        aList, &MyDouble::mapFunction, &ReduceAccumulator::reduceFunction);
}

您可以选择......在这种情况下,作为成员执行 reduceFunction 可能会更好。但是更改输入序列类型有点难看,而且这不是过程参数的正确位置——你需要一个函数对象。

(还要记住,map 函数可以达到的可写状态会破坏 MapReduce 的并行性。map 操作应该只通过其结果生成输出,因此它们保持独立......)

于 2011-11-01T01:29:44.500 回答