调试和发布版本中的执行时间很奇怪

Strange execution time in Debug and Release versions

本文关键字:执行时间 版本 布版本 调试      更新时间:2023-10-16

我在VS2010中开始使用并行模式库,应用程序给了我预期的结果,但当我对调试版本和发布版本进行基准测试时,我在发布版本中得到了奇怪的执行时间,如下所示调试版本:"连续持续时间:1014"并行持续时间:437"发布版本"连续持续时间:31"并行持续时间:484"

这是我的应用程序代码

double DoWork(int workload)
{
    double result=0;
    for(int i =0 ; i < workload;i++)
    {
        result +=sqrt((double)i * 4*3) + i* i;
    }
    return result;
}
vector<double> Seqential()
{
    vector<double> results(100);
    for(int i = 0 ; i <100 ; i++)
    {
        results[i] = DoWork(1000000);
    }
    return results;
}
vector<double> Parallel()
{
     vector<double> results(100);
     parallel_for(0,(int)100,1,[&results](int i)
     {
         results[i] = DoWork(1000000);
     });
     return results;
}
double Sum(const vector<double>& results)
{
    double result =0;
    for(int i = 0 ; i < results.size();i++)
        result += results[i];
    return result;
}
int main()
{
    DWORD start = GetTickCount();
    vector<double> results = Seqential();
    DWORD duration = GetTickCount() - start;
    cout<<"Sequential Duration : "<<duration <<"  Result : " <<Sum(results) << endl;
    start = GetTickCount();
    results = Parallel();
    duration = GetTickCount() - start;
    cout<<"Prallel Duration : "<<duration <<"  Result : " <<Sum(results) << endl;
    system("PAUSE");
    return 0;
}

IIRC,C++11允许编译器深入到函数中,以便在编译时预计算常量表达式,甚至是像sqrt这样的函数。因此,您的Sequential版本可能会一直优化到结果表。如果可能的话,您可能需要查看Sequential生成的程序集,看看它是否看起来过于简化,或者可能完全优化了。

关于DoWork,没有什么是不能在编译时计算的。

问题不在于Parallel速度慢,而在于Seqential速度太快:

  • Seqential中,编译器看到DoWork总是会产生相同的结果,因此调用它100次的循环被优化掉,DoWork最终只被调用一次
  • 编译器不够聪明,无法以完全相同的方式优化parallel_for,因此它最终完成了实际工作(实际上是实际工作的100倍)

如果使DoWork依赖于循环计数器,那么不同的调用现在将产生不同的结果,因此没有多余的调用,因此编译器将无法进行任何优化。

例如:

#include <vector>
#include <iostream>
#include <math.h>
#include <ppl.h>
#include <Windows.h>
using namespace std;
using namespace Concurrency;
double DoWork(int workload, int outer_i)
{
double result=0;
for(int i =0 ; i < workload;i++)
{
    result +=sqrt((double)i * 4*3) + i* i;
}
result += outer_i;
return result;
}
vector<double> Seqential()
{
vector<double> results(100);
for(int i = 0 ; i <100 ; i++)
{
    results[i] = DoWork(1000000, i);
}
return results;
}
vector<double> Parallel()
{
vector<double> results(100);
parallel_for(0,(int)100,1,[&results](int i)
{
    results[i] = DoWork(1000000, i);
});
return results;
}
double Sum(const vector<double>& results)
{
double result =0;
for(int i = 0 ; i < results.size();i++)
    result += results[i];
return result;
}
int main()
{
DWORD start = GetTickCount();
vector<double> results = Seqential();
DWORD duration = GetTickCount() - start;
cout<<"Sequential Duration : "<<duration <<"  Result : " <<Sum(results) << endl;
start = GetTickCount();
results = Parallel();
duration = GetTickCount() - start;
cout<<"Prallel Duration : "<<duration <<"  Result : " <<Sum(results) << endl;
system("PAUSE");
return 0;
}

当由Visual C++2010在Release配置下构建并在四核CPU上运行时,将打印:

Sequential Duration : 1607  Result : 1.68692e+015
Prallel Duration : 374  Result : 1.68692e+015

(顺便说一句,你真的应该考虑更好地格式化你的代码。)

可能发生的情况是,生成多个线程的开销比简单地计算结果花费更多的时间。在Release版本中,编译器能够进行大量优化,因此与设置线程和拆除线程所需的工作量相比,DoWork内部所做的工作量要小得多。

如果您让DoWork做更多的工作(例如通过多次循环),您将看到更符合您期望的结果。