fread OpenMP 线程中的性能下降

Posted

技术标签:

【中文标题】fread OpenMP 线程中的性能下降【英文标题】:fread slow performance in OpenMP threads 【发布时间】:2011-11-14 11:44:43 【问题描述】:

我使用 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,但效果不大。

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

【问题讨论】:

我的朋友给了我一个好建议:使用 ramdisk 存储文件。 3000 个 40 MB 的文件相当于 120 GB。即使不是特别大,这个数量的 RAM 也是相当大的。 【参考方案1】:

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

那么你最好开始相信。与 CPU 相比,磁盘速度非常慢。并行 I/O 通常仅在您从多个源(例如单独的磁盘或网络连接)读取时才有帮助。它可以很好地解决延迟问题,但不能解决带宽问题。

尝试以串行方式一次性读取所有数据,然后在并行循环中对其进行处理。

【讨论】:

“尝试一次读取所有数据” - 是的,我已经完成了 :)【参考方案2】:

磁盘读数无法并行化*:无论您有 1 个还是 24 个 CPU 内核都不会改变您的磁盘 I/O 吞吐量。

如果 一个 performCalculations(); 调用比读取 一个 40 MB 文件的内容更快,则无需在多个 CPU 上进行并行处理。您的程序执行受到磁盘带宽的限制。你测量过这个吗?

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

【讨论】:

【参考方案3】:

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

有几个解决方案:

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

【讨论】:

管道并行是什么意思?您能否编辑您的答案以更详细地说明?

以上是关于fread OpenMP 线程中的性能下降的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 中的线程任务调度

多个 OpenMP 线程读取(不写入)共享变量的性能成本?

单核CPU使用openmp,会大幅度提高计算性能吗?

OpenMP 性能影响:私有指令与在构造内部声明变量

OpenMP C++ 中的线程

如何不等待 OpenMP 中的其他线程?