0

我写了一个使用std::vector<double>相当多的例程。它运行得相当慢,AQTime 似乎暗示我正在构建大量向量,但我不确定我为什么会这样。在某些情况下,我的示例运行迭代 10 次。每次迭代将 3 c 个约 400 个点的数组复制到向量中,并创建 3 个新的相同大小的向量用于输出。每个输出点可能是从 2 个输入向量中求和最多 20 个点的结果,最坏的情况是 10*400*3*2*20 = 480,000 次取消引用。令人难以置信的是,分析器表明某些 std:: 方法被调用了 4600 万次。我怀疑我做错了什么!

一些代码:

vector<double>gdbChannel::GetVector() {
   if (fHaveDoubleData & (fLength > 0)) {
      double * pD = getDoublePointer();
      vector<double>v(pD, pD + fLength);

      return v;
   } else {
      throw(Exception("attempt to retrieve vector on empty line")); ;
   }
}

void gdbChannel::SaveVector(GX_HANDLE _hLine, const vector<double> & V) {
   if (hLine != _hLine) {
      GetLine(_hLine, V.size(), true);
   }
   GX_DOUBLE * pData = getDoublePointer();
   memcpy(pData, &V[0], V.size()*sizeof(V[0]));
   ReplaceData();
}

///This routine gets called 10 times
 bool SpecRatio::DoWork(GX_HANDLE_PTR pLine) {
   if (!(hKin.GetLine(*pLine, true) && hUin.GetLine(*pLine, true) && hTHin.GetLine(*pLine, true))) {
      return true;
   }
   vector<double>vK = hKin.GetVector();
   vector<double>vU = hUin.GetVector();
   vector<double>vTh = hTHin.GetVector();

   if ((vK.size() == 0) || (vU.size() == 0) || (vTh.size() == 0)) {
      return true;
   }
   ///TODO: confirm all vectors the same lenghth
   len = vK.size();
   vUK.clear();  // these 3 vectors are declared as private class members
   vUTh.clear();
   vThK.clear();
   vUK.reserve(len);
   vUTh.reserve(len);
   vThK.reserve(len);

   // TODO: ensure everything is same fidincr, fidstart and length

   for (int i = 0; i < len; i++) {
      if (vK.at(i) < MinK) {
         vUK.push_back(rDUMMY);
         vUTh.push_back(rDUMMY);
         vThK.push_back(rDUMMY);
      } else {
         vUK.push_back(RatioPoint(vU, vK, i, UMin, KMin));
         vUTh.push_back(RatioPoint(vU, vTh, i, UMin, ThMin));
         vThK.push_back(RatioPoint(vTh, vK, i, ThMin, KMin));
      }

   }
   hUKout.setFidParams(hKin);
   hUKout.SaveVector(*pLine, vUK);
   hUTHout.setFidParams(hKin);
   hUTHout.SaveVector(*pLine, vUTh);
   hTHKout.setFidParams(hKin);
   hTHKout.SaveVector(*pLine, vThK);
   return TestError();
}

double SpecRatio::VValue(vector<double>V, int Index) {
   double result;
   if ((Index < 0) || (Index >= len)) {
      result = 0;

   } else {
      try {
         result = V.at(Index);
         if (OasisUtils::isDummy(result)) {
            result = 0;
         }
      }
      catch (out_of_range) {
         result = 0;
      }
   }
   return result;
}

double SpecRatio::RatioPoint(vector<double>Num, vector<double>Denom, int Index, double NumMin, double DenomMin) {
   double num = VValue(Num, Index);
   double denom = VValue(Denom, Index);
   int s = 0;
   // Search equalled 10 in this case
   while (((num < NumMin) || (denom < DenomMin)) && (s < Search)) {
      num += VValue(Num, Index - s) + VValue(Num, Index + s);
      denom += VValue(Denom, Index - s) + VValue(Denom, Index + s);
      s++;
   }
   if ((num < NumMin) || (denom < DenomMin)) {
      return rDUMMY;
   } else {
      return num / denom;
   }

}

AQTime 的主要违规者是:

std::_Uninit_copy >、double *、std::allocator > 3.65 秒和 115731 次命中

std::_Construct 1.69 秒和 46450637 次点击

std::_Vector_const_iterator >::operator !=1.66 秒和 46566395 次点击等等...

std::allocator<double>::construct,
operator new,
std::_Vector_const_iterator<double, std::allocator<double> >::operator ++,std::_Vector_const_iterator<double, std::allocator<double> >::operator * std::_Vector_const_iterator<double, std::allocator<double> >::operator ==

每个都被调用超过 4600 万次。

我显然做错了导致所有这些对象被创建。谁能看到我的错误?

4

2 回答 2

2

这是因为您正在按值传递函数参数。每次std::vector按值传递 a 时,都必须制作向量的完整副本。

更改这些:

double SpecRatio::VValue(vector<double>V, int Index) {

double SpecRatio::RatioPoint(vector<double>Num, vector<double>Denom...

至:

double SpecRatio::VValue(const vector<double> &V, int Index)

double SpecRatio::RatioPoint(const vector<double> &Num, const vector<double> &Denom...

因为对于您的使用,您实际上不需要制作这些向量的单独副本。

于 2012-07-10T03:21:34.313 回答
1

由于您传递和返回它们的方式(“按值”),您在几个地方复制向量的效率很低(“深度”)。例如,您的VValue()方法正在复制其向量参数,就像您的RatioPoint()方法一样,其中两个向量参数都(不必要地)被完整复制。相反,您可能希望将向量参数作为 a 传递const vector<double>&(即“通过引用”,就像您在 中所做的那样SaveVector())。

此外,您的 GetVector() 方法可能会返回向量的副本,尽管如果编译器对其进行优化,这可能会避免(正如 walrii 在回复我最初的错误帖子时指出的那样)。如果您使用的是 C++-11,则可以返回一个可移动的(正如 walrii 也指出的那样)。如果没有这些,解决方案会有点棘手——您可能会考虑在堆上分配向量并返回一个共享或自动指针指向它。

于 2012-07-10T03:20:03.253 回答