在OpenMP线程中表现缓慢

fread slow performance in OpenMP threads

本文关键字:缓慢 OpenMP 线程      更新时间:2023-10-16

我使用Intel Xeon x2(24内核)和Windows Server 2008。
试图并行化我的c++程序。模板代码:

vector< string > files;
vector< vector< float > > data; 
...
data.resize( files.size() ); 
#pragma omp parallel for 
for (int i=0; i<files.size(); i++) { // Files count is about 3000
    FILE *f = fopen(files[i].c_str(), "rb"); 
    // every file is about 40 mb
    data[i].resize(someSize);
    fread(&data[i][0], sizeof(float), someSize, f); 
    fclose(f);
    ...
    performCalculations();  
}

CPU使用率仅为0 ~ 5%。
当我插入代替的fread(&data[I][0], sizeof(float), someSize, f):

for (int j=0; j<data.size(); j++) {
    data[i][j] = rand(); 
}

CPU使用率增加到100%。
我已经尝试过使用fstream和WinApi ReadFile,但是效果不明显。

我做错了什么?我不相信磁盘读取会这么慢…

我不相信磁盘读取可以这么慢…

那你最好开始相信。与cpu相比,磁盘慢得令人难以置信。并行I/O通常只在从多个源(如单独的磁盘或网络连接)读取数据时才有帮助。它可以很好地解决延迟问题,但不能解决带宽问题。

尝试一次连续读取所有数据,然后在并行循环中处理。

磁盘读取不能并行*:无论您有1个或24个CPU内核都不会改变您的磁盘I/O吞吐量。

如果一个 performCalculations();调用比读取一个的40mb文件的内容要快,那么就没有必要在多个CPU上并行化。您的程序执行受到磁盘带宽的限制。你测量过这个吗?

*:可以,但是需要硬件。就像在多个CPU上并行执行需要实际的多个CPU硬件一样,并行磁盘I/O需要更多的磁盘I/O硬件。

如果您使用的是传统的HDD,则不会有任何明显的加速,因为会有许多并发的文件读取。硬盘大多不能处理这样的当前文件读取。这就是为什么只有0-5%的CPU占用,这意味着大多数并行循环只是等待文件操作。(注意,只要多个文件读取在不同的物理磁盘或盘片上,磁盘读取就可以并行化。)

有两个解决方案:

  1. 尝试使用可以支持更好的随机/并发访问的SSD。
  2. 虽然要解释这个答案中的所有内容并不容易,但请尝试使用管道并行性。OpenMP并不适合流水线,但是TBB支持一个易于使用的流水线模板。管道允许文件读取步骤和其他计算步骤,因此您可以有一个不错的加速。当然,应该有足够的计算量。