0

我发现 openmp 不支持 while 循环(或者至少不太喜欢它们)。而且也不喜欢 ' != ' 运算符。

我有这段代码。

int count = 1;
#pragma omp parallel for
    while ( fgets(buff, BUFF_SIZE, f) != NULL )
    {
        len = strlen(buff);
        int sequence_counter = segment_read(buff,len,count);
        if (sequence_counter == 1)
        {
            count_of_reads++;
            printf("\n Total No. of reads: %d \n",count_of_reads);
        }
    count++;
    }

关于如何管理这个的任何线索?我在某处(包括关于 stackoverflow 的另一篇文章)读到我可以使用管道。那是什么 ?以及如何实施?

4

3 回答 3

13

太糟糕了,人们这么快就选择了最佳答案。这是我的答案。
首先,您应该使用 fread 之类的东西将文件读入缓冲区。这非常快。可以在此处找到如何执行此操作的示例http://www.cplusplus.com/reference/cstdio/fread/

然后您可以与 OpenMP 并行操作缓冲区。我已经为你实现了大部分。下面是代码。您没有提供该segment_read功能,因此我创建了一个虚拟功能。我使用了 C++ 中的一些函数,例如 std::vector 和 std::sort ,但只要多做一些工作,你也可以在纯 C 中做到这一点。

编辑: 我编辑了这段代码,并且能够删除排序和关键部分。

我编译了g++ foo.cpp -o foo -fopenmp -O3

#include <stdio.h>
#include <omp.h>
#include <vector>

using namespace std;

int segment_read(char *buff, const int len, const int count) {
  return 1;  
}

void foo(char* buffer, size_t size) {
    int count_of_reads = 0;
    int count = 1;
    std::vector<int> *posa;
    int nthreads;

    #pragma omp parallel 
    {
        nthreads = omp_get_num_threads();
        const int ithread = omp_get_thread_num();
        #pragma omp single 
        {
            posa = new vector<int>[nthreads];
            posa[0].push_back(0);
        }

        //get the number of lines and end of line position
        #pragma omp for reduction(+: count)
        for(int i=0; i<size; i++) {
            if(buffer[i] == '\n') { //should add EOF as well to be safe
                count++;
                posa[ithread].push_back(i);
            }
        }

        #pragma omp for     
        for(int i=1; i<count ;i++) {    
            const int len = posa[ithread][i] - posa[ithread][i-1];
            char* buff = &buffer[posa[ithread][i-1]];
            const int sequence_counter = segment_read(buff,len,i);
            if (sequence_counter == 1) {
                #pragma omp atomic
                count_of_reads++;
                printf("\n Total No. of reads: %d \n",count_of_reads);
            }

        }
    }
    delete[] posa;
}

int main () {
  FILE * pFile;
  long lSize;
  char * buffer;
  size_t result;

  pFile = fopen ( "myfile.txt" , "rb" );
  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

  // obtain file size:
  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile);

  // allocate memory to contain the whole file:
  buffer = (char*) malloc (sizeof(char)*lSize);
  if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

  // copy the file into the buffer:
  result = fread (buffer,1,lSize,pFile);
  if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

  /* the whole file is now loaded in the memory buffer. */
  foo(buffer, result);
  // terminate


  fclose (pFile);
  free (buffer);
  return 0;
}
于 2013-05-29T22:14:55.250 回答
4

在 OpenMP 中实现“并行 while”的一种方法是使用创建任务的 while 循环。这是一个总体草图:

void foo() {
    while( Foo* f = get_next_thing() ) {
#pragma omp task firstprivate(f)
        bar(f);
    }
#pragma omp taskwait
}

对于循环 fgets 的特定情况,请注意 fgets 具有固有的顺序语义(它获取“下”行),因此需要在启动任务之前调用它。每个任务对 fgets 返回的数据的自己的副本进行操作也很重要,这样对 fgets 的调用不会覆盖前一个任务正在操作的缓冲区。

于 2013-05-29T17:31:36.887 回答
1

首先,即使它非常接近,但 openmp 并不会神奇地使您的代码并行。它可以使用,for因为for它具有可以理解的下限和上限。Openmp 使用这些界限在不同线程之间划分工作。

while循环不可能有这样的事情。

其次,您希望您的任务如何并行化?您正在从文件中读取,其中顺序访问可能会比并行访问提供更好的性能。您可能会并行化segment_read(基于其实现)。

或者,您可能希望将文件读取与处理重叠。为此,您需要使用更底层的函数,例如 Unix 的openread函数。然后,进行异步读取,这意味着您发送读取请求,处理最后一个读取块,然后等待读取请求完成。例如,搜索“linux asynchronous io”以了解更多信息。

使用管道实际上可能对您没有多大帮助。这将取决于我不太熟悉的管道的许多内部结构。但是,如果您有足够大的内存,您可能还需要考虑先加载整个数据,然后再进行处理。这样,加载数据会尽可能快(按顺序)完成,然后您可以并行处理它。

于 2013-05-29T15:21:45.797 回答