并行for比连续慢

时间:2016-01-24 16:28:32

标签: c++ parallel-processing openmp

我的程序应执行单词和文本的平行不同轮换。

如果您不知道这意味着什么:旋转" BANANA"是

  • 香蕉
  • ANANAB
  • NANABA
  • ANABAN
  • 菜花
  • ABANAN

(只需将第一个字母放到最后。)

vector<string> rotate_sequentiell( string* word )
{
vector<string> all_rotations;

for ( unsigned int i = 0; i < word->size(); i++ )
{
    string rotated = word->substr( i ) + word->substr( 0,i );
    all_rotations.push_back( rotated );
}

if ( verbose ) { printVec(&all_rotations, "Rotations"); }


return all_rotations;
}

我们应该能够做到这一点。我想把两个字母一次移到最后,而不是只移动一个字母,所以例如我们采取香蕉 以te&#34; BA&#34;到最后并获得NANA BA,这是上面列表中的第三个条目。

我像这样实现了它

vector<string> rotate_parallel( string* word )
{
vector<string> all_rotations( word->size() );

#pragma omp parallel for
for ( unsigned int i = 0; i < word->size(); i++ )
{
    string rotated = word->substr( i ) + word->substr( 0,i );
    all_rotations[i] = rotated;
}

if ( verbose ) { printVec(&all_rotations, "Rotations"); }

return all_rotations;
}

我预先计算了可能的旋转次数并使用了#pragma omp parallel,所以它应该按照我的想法行事。

为了测试这些功能,我有一个40KB的大文本文件,意图是&#34;旋转&#34;。我想拥有一个巨大文本的所有不同轮换。

现在发生的事情是,顺序过程需要4.3秒,而并行程序需要6.5秒。

为什么会这样?我做错了什么?

这是我衡量时间的方式:

clock_t start, finish;
start = clock();
bwt_encode_parallel( &glob_word, &seperator );
finish = clock();
cout << "Time (seconds): "
     << ((double)(finish - start))/CLOCKS_PER_SEC;

我用

编译我的代码

g ++ -O3 -g -Wall -lboost_regex -fopenmp -fmessage-length = 0

1 个答案:

答案 0 :(得分:2)

与顺序版相比,并行版有2个额外工作源: (1)启动线程的开销,和 (2)线程之间的协调和锁定。

(1)的影响当数据集变大时应该减少,并且可能无论如何都不值2秒,但这将设置并行化小作业的限制。

(2)在你的情况下可能主要是由omp为线程分配任务,以及不同的线程为2个中间子串进行内存分配和最后的字符串&#34;旋转&#34; - 内存分配例程可能必须先得到一个全局锁,然后才能为你保留一块堆。

在单个线程中预分配最终存储并指导OMP在每个线程的大(2048)次迭代块中运行并行循环,从而倾斜结果以支持并行执行。对于单线程,我得到大约700ms,对于多线程版本,我得到大约330ms,代码如下:

 enum {SZ = 40960};
 std::string word;
 word.resize(SZ);
 for (int i = 0; i < SZ; i++) {
   word[i] = (i & 127) + 1;  // put stuff into the word
 }
 std::vector<std::string> all_rotations(SZ);
 clock_t start, finish;
 start = clock();
 for (int i = 0; i < (int)word.size(); i++) {
   all_rotations[i].reserve(SZ);
 }
 #pragma omp parallel for schedule (static, 2048)
 for (int i = 0; i < (int)word.size(); i++) {
   std::string rotated = word.substr(i) + word.substr(0, i);
   all_rotations[i] = rotated;
 }
 finish = clock();
 printf("Time (seconds): %0.3lf\n", ((double)(finish - start))/CLOCKS_PER_SEC);

最后,当您需要挖掘轮廓转换的结果时,您不一定需要N个包含N个字符的字符串副本。它可以节省空间和处理,将字符串视为环形缓冲区,并从缓冲区中的不同偏移量读取每个旋转。