通过引用传递太多参数可能效率低下?

时间:2017-04-12 15:43:32

标签: c++ parallel-processing openmp intel

Disclamer:我正在使用英特尔编译器2017,如果您想知道我为什么这样做,请转到问题的最后。

我有这段代码:

class A{
  vector<float> v;
  ...
  void foo();
  void bar();
}

void A::foo(){
  for(int i=0; i<bigNumber;i++){
    //something very expensive
    //call bar() many times per cycle;
  }
}

void A::bar(){
  //...
  v.push_back(/*something*/);
}

现在,我们假设我要并行foo(),因为它非常昂贵。但是,由于#pragma omp parallel for,我无法简单地使用v.push_back()

据我所知,这里有两种选择:

  1. 我们使用#pragma omp critical
  2. 我们为每个帖子创建v的本地版本,然后我们在并行部分的末尾联合它们,或多或少按照here解释。
  3. 解决方案1.通常被认为是一个糟糕的解决方案,因为竞争条件会产生一致的开销。

    但是,解决方案2.需要以这种方式修改bar()

    class A{
      vector<float> v;
      ...
      void foo();
      void bar(std::vector<float> &local_v);
    }
    
    void A::foo(){
      #pragma omp parallel
      {
        std::vector<float> local_v;
        #pragma omp for
        for(int i=0; i<bigNumber;i++){
          //something very expensive
          //call bar(local_v) many times per cycle;
        }
        #pragma omp critical
        {
          v.insert(v.end(), local_v.begin(), local_v.end());
        }
      }
    }
    
    void A::bar(std::vector<float> &local_v){
      //...
      v.push_back(/*something*/);
    }
    

    到目前为止一切顺利。现在,我们假设不仅有v,而且还有10个向量,比如v1v2,...,v10,或者无论如何10个共享变量。此外,我们假设bar不是直接在foo()内调用,而是在许多嵌套调用之后调用。像foo()调用foo1(std::vector<float> v1, ..., std::vector<float> v10)调用foo2(std::vector<float> v1, ..., std::vector<float> v10),重复此嵌套调用很多次,直到最后一次调用bar(std::vector<float> v1, ..., std::vector<float> v10)

    所以,这看起来像是一个可维护性的噩梦(我必须修改所有嵌套函数的所有标题和调用)......但更重要的是:我们同意通过引用传递是有效的,但它&#39;总是一个指针副本。如您所见,这里有很多指针被复制多次。所有这些副本是否有可能导致效率低下?

    实际上我最关心的是性能,所以如果你告诉我&#34; nah,它很好,因为编译器是超级智能的,他们做了一些巫术,所以你可以复制一万亿个引用,并且有性能没有下降&#34;那就没事了,但我不知道这样的巫术是否存在。

    为什么我这样做: 我试图并行化this代码。特别是,我将while here重写为可以并行化的for,但如果您按照代码进行回调,则会发现回拨调用来自hereonAffineShapeFound,它会修改共享对象keys的状态。对于许多其他变量,这种情况会发生,但这是最深的&#34;此代码的大小写。

1 个答案:

答案 0 :(得分:1)

a::Bar()a::Bar(std::vector<float> & v)之间的直接比较中,不同之处在于第二个版本必须将堆栈的大小增加8个字节,而不是原始版本必须做的。在性能方面,这是一个非常小的效果:无论函数是否包含参数,都必须调整堆栈指针(因此唯一真正的区别是单个指针复制,甚至可能根据编译器进行优化) ),就函数本身的实际性能而言,不断向std::vector添加元素将是一个更昂贵的操作,特别是如果向量需要重新分配(这可能经常发生,取决于向量需要获得的大小,这意味着这些成本将远远超过指针副本的成本。

所以,简短的版本:坚持参考。