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

Posted

技术标签:

【中文标题】多线程应用程序中最快的文件读取【英文标题】:Fastest file reading in a multi-threaded application 【发布时间】:2012-05-27 10:12:13 【问题描述】:

我必须将 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

有没有办法进一步优化?

【问题讨论】:

当有足够的数据可用时,也许您可​​以与 i/o 并行启动填充线程。 老实说,我有点惊讶您能够通过从多个线程读取同一个文件来获得 任何 性能改进...在进行基准测试时,您是确保文件实际上是从磁盘读取的,而不是从缓存中读取的? @aix 我仅使用了 2 个线程。我已经并行化了预处理部分,这是在将数据读入内存之后。 我知道提高磁盘读取性能的唯一方法是:1)从压缩源读取数据。 2) 使用速度更快的磁盘或 RAID 阵列。或 3) 将数据拆分到单独的磁盘上,每个磁盘读取 1 个线程。通常,如果单个线程跟不上你的磁盘读取时间,你就有大问题了。 以二进制形式存储您的数据。如果每个矩阵元素最多可以取 256 个不同的值,那么我们在这里看到的是 64MB,这应该很容易被现代硬件处理。然后,您还可以将文件直接内存映射到您的程序中。 【参考方案1】:

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

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

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

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

【讨论】:

并行读取文件,他正在将字符串从内存并行转换为 int8_t`s。这没有什么问题。 我从未声称这有什么问题。事实上,我建议将其与读取数据的线程重叠。【参考方案2】:

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

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

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

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

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

【讨论】:

以上是关于多线程应用程序中最快的文件读取的主要内容,如果未能解决你的问题,请参考以下文章

多线程的优点

多线程的优点

Java多线程的优点

迭代文件系统的最快方法

清除具有大量形状/多线程的组的最快方法

PythonStudy——多线程编程