在多线程应用程序中读取最快的文件

Fastest file reading in a multi-threaded application

本文关键字:文件 读取 多线程 应用程序      更新时间:2023-10-16

我必须将一个 8192x8192 的矩阵读入内存。我想尽快完成。
现在我有这个结构:

char inputFile[8192][8192*4]; // I know the numbers are at max 3 digits
int8_t matrix[8192][8192]; // Matrix to be populated
// Read entire file line by line using fgets
while (fgets (inputFile[lineNum++], MAXCOLS, fp));
//Populate the matrix in parallel, 
for (t = 0; t < NUM_THREADS; t++){
    pthread_create(&threads[t], NULL, ParallelRead, (void *)t);
}

在函数ParallelRead中,我解析每一行,执行atoi并填充矩阵。并行性是逐行的,就像线程 t 解析行t, t+ 1 * NUM_THREADS..

在具有 2 个线程的双核系统上,这需要

Loading big file (fgets) : 5.79126
Preprocessing data (Parallel Read) : 4.44083

有没有办法进一步优化这一点?

这样做是个坏主意。 如果您有足够的内核,但仍然只有一个硬盘,则线程可以获得更多的 CPU 周期。 因此,线程不可避免地无法提高读取文件数据的速度。

他们实际上使情况变得更糟。 按顺序访问文件时,从文件中读取数据的速度最快。 这最大限度地减少了读取器磁头搜索的数量,这是迄今为止磁盘驱动器上最昂贵的操作。 通过将读取拆分到多个线程中,每个线程读取文件的不同部分,您正在使读取器头部不断来回跳跃。 对吞吐量非常非常不利。

仅使用一个线程读取文件数据。 您可以通过在加载文件数据块后启动线程来将其与文件数据的某些计算周期重叠。

请注意测试效果。 当您重新运行程序时,通常在稍微调整代码之后,程序可能会在文件系统缓存中找到文件数据,因此不必从磁盘读取。 这是非常快的内存总线速度,内存到内存的副本。 很可能在您的数据集上,因为它不是很大,并且很容易适应现代机器拥有的 RAM 量。 这(通常(不会在生产计算机上发生。 因此,请务必清除缓存以获得实际数字,无论您的操作系统需要什么。

值得考虑的一件事是分配两个较小的输入缓冲区(假设每个缓冲区为 200 行(。

然后让一个线程将数据读入输入缓冲区。当一个输入缓冲区已满时,将其传递给执行解析的第二个线程。第二个线程可以使用线程池进行并发解析(检查 openMP(。

您必须使用锁/互斥锁来确保任一线程具有独占访问权限。

这会更好,因为解析现在与读取文件并发,并且您对缓冲区的内存访问更加本地,并且适合您的 CPU 缓存。这可以提高读取和解析速度。

如果 fgets 是瓶颈,您还可以将文件作为二进制文件读入内存。这可以提高读取速度,但需要您进行额外的解析,并使上述优化更难执行。

尝试使用类似 fread 的东西加载字符数组的父线程,将 1 io 中的所有内容作为大字符串加载。

让父级遍历字符串,找到 1 条线,或者根据大小计算第一行的位置。 将该行的处理交给线程。 下一行,冲洗,重复,直到EOF。 与线程同步。做。

通过文件 I/O 可以获得的最佳性能是通过内存映射。这是一个例子。我会从单线程设计开始,如果加载后处理被证明是一个瓶颈,请使其并行。