c++ - C++中线程读取文件

标签 c++ linux io pthreads getline

我编写了一个程序(使用 FFTW)对一些用 OpenFOAM 编写的数据文件执行傅立叶变换。

程序首先找到每个数据文件的路径(在我当前的示例中为 501 个文件),然后在线程之间拆分路径,这样线程 0 获得路径 0->61,线程 1 获得 62-> 123 左右,等等,然后在最后串行运行剩余的文件。

我在整个代码中实现了计时器,以尝试查看它的瓶颈所在,因为串行运行每个文件大约需要 3.5 秒,而并行运行 8 个文件所需的时间约为 21 秒(比 8x3.5 的 28 秒减少了(串行时间),但没有那么多)

下面是我的代码中有问题的部分

if (DIAG_timers) {readTimer = timerNow();}
for (yindex=0; yindex<ycells; yindex++)
{
    for (xindex=0; xindex<xcells; xindex++)
    {
        getline(alphaFile, alphaStringValue);
        convertToNumber(alphaStringValue, alphaValue[xindex][yindex]);
    }
}
if (DIAG_timers) {endTimerP(readTimer, tid, "reading value and converting", false);}

这里,timerNow() 返回时钟值,endTimerP 计算已经过去的时间,单位为 ms。 (其余参数与它在并行线程中运行有关,以避免为每个循环等输出 8 行,以及计时器测量内容的描述)。

convertToNumber 获取 alphaStringValue 上的值,并将其转换为 double 值,然后将其存储在 alphaValue 数组中。

alphaFile 是一个 std::ifstream 对象,而 alphaStringValue 是一个 std::string,它存储每一行​​的文本。

要读取的文件每个大约 40MB(仅比 5120000 多几行,每行仅包含一个值,介于 0 和 1 之间(在大多数情况下 == (0||1) ),我有 16GB 的RAM,所以将所有文件复制到内存肯定是可能的,因为一次只能打开 8 个(每个线程 1 个)。我不确定 mmap 是否会做得更好?stackoverflow 上的几个线程争论 mmap 与更多的优点直接读取操作,特别是对于顺序访问,所以我不知道这是否有益。

我尝试用一​​个互斥量围绕代码块,这样一次只有一个线程可以运行该 block ,以防读取多个文件通过模糊的随机访问导致缓慢的 IO,但这只是将进程降低到大致串行速度次。

任何允许我更快地运行此部分的建议,可能是通过复制文件,或者实际上是其他任何方式,将不胜感激。

编辑:

template<class T> inline void convertToNumber(std::string const& s, T &result)
{
    std::istringstream i(s);
    T x;
    if (!(i >> x))
        throw BadConversion("convertToNumber(\"" + s + "\")");
    result = x;
}

原来是慢的部分。我认为这是由于每个文件创建了 500 万个字符串流,然后测试了 500 万个 if 条件?用 TonyD 的建议替换它大概可以消除捕获错误的可能性,但可以节省大量(至少在这种受控情况下)不必要的操作。

最佳答案

The files to be read are approximately 40MB each (just a few lines more than 5120000, each containing only one value, between 0 and 1 (in most cases == (0||1) ), and I have 16GB of RAM, so copying all the files to memory would certainly be possible,

是的。但是将它们加载到那里仍将计入您的进程的挂钟时间,除非它们在不久之前已被另一个进程读取。

since only 8 (1 per thread) should be open at once.

由于在进程开始之前没有加载到内存中的任何文件都必须加载,因此加载将计入进程挂钟时间,因此一次打开多少文件都没有关系。任何不是缓存的都会减慢进程。

I am unsure if mmap would do this better?

不,它不会。 mmap 更快,但因为它保存了从内核缓冲区到应用程序缓冲区和某些系统的拷贝调用开销(使用 read 时,您为每个页面执行一个内核条目,而使用预读读取的 mmap 页面不会导致进一步的页面错误)。但如果文件尚未缓存,它不会为您节省从磁盘读取文件的时间。

mmap 不会在内存中加载任何内容。内核将数据从磁盘加载到内部缓冲区,即页面缓存。 read 将数据从那里复制到您的应用程序缓冲区,而 mmap 直接在您的地址空间中公开部分页面缓存。但在任何一种情况下,数据都是在第一次访问时获取并保留在那里,直到内存管理器丢弃它们以重用内存。页面缓存是全局的,因此如果一个进程导致某些数据被缓存,下一个进程将更快地获取它们。但如果是在较长时间后首次访问,则必须读取数据,这将以完全相同的方式影响 readmmap

由于并行化进程并没有显着缩短时间,似乎大部分时间都是实际的 I/O。因此您可以进一步优化,mmap 可以提供帮助,但不要期望太多。提高 I/O 时间的唯一方法是获得更快的磁盘。


您应该能够使用 getrusage(2) 要求系统告诉您在 CPU 上花费了多少时间以及在等待数据 (I/O) 上花费了多少时间| (在每个线程结束时调用它以获取该线程的数据)。因此,您可以确认 I/O 花费了多少时间。

关于c++ - C++中线程读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21228501/

相关文章:

linux - 如果设备已被 "spidev"驱动程序访问,如何添加 SPI 设备驱动程序?

linux - 树莓派 Autostart.desktop 终端

java - 我在java中使用I/O,当我使用in.nextInt从第一个返回再次读取文件时,我需要一个函数

c++ - 如何获取其他命令行界面程序的输出?

c++ - Visual Studio malloc 限制

c++ - 将多参数函数传递给宏

java - 运算符 reinterpret_cast<const uint8_t*> 后出现错误 "core dumped"

C++ 选择语句返回 true

c - Arm Cortex A8 上的分析

python - 如何打开一个ascii编码的文件为UTF8?