我必须将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
有没有办法进一步优化这个?
答案 0 :(得分:24)
这样做是个坏主意。如果你有足够的内核但是你仍然只有一个硬盘,那么线程可以获得更多的cpu周期。因此线程不可避免地无法提高读取文件数据的速度。
他们实际上让事情变得更糟。按顺序访问文件时,从文件中读取数据的速度最快。这最大限度地减少了读取器磁头的数量,这是磁盘驱动器上最昂贵的操作。通过将读数分成多个线程,每个线程读取文件的不同部分,您使读者头部不断地来回跳跃。非常非常糟糕的吞吐量。
仅使用一个线程来读取文件数据。通过在加载一大块文件数据后启动一个线程,您可以将它与文件数据上的一些计算周期重叠。
注意测试效果。当您重新运行程序时,通常在稍微调整代码之后,程序可能会在文件系统缓存中找回文件数据,因此不必从磁盘读取。这是非常快的内存总线速度,内存到内存的副本。很可能在你的数据集上,因为它不是很大,很容易适应现代机器的RAM量。这(通常)不会在生产机器上发生。所以一定要清除缓存以获得真实的数字,无论你在操作系统上花多少钱。
答案 1 :(得分:2)
值得考虑的一件事是分配两个较小的输入缓冲区(比如它们将分别为200条线)。
然后让一个线程将数据读入输入缓冲区。 当一个输入缓冲区已满时,将其传递给执行解析的第二个线程。第二个线程可以使用线程池进行并发解析(检查openMP)。
您必须使用锁/互斥锁来确保任一线程都具有独占访问权。
这样会更好,因为解析现在与读取文件并发,并且您对缓冲区的内存访问更加本地化并且适合您的CPU缓存。这可以提高读取和解析速度。
如果fgets是瓶颈,您还可以将文件作为二进制文件读入内存。这可以提高读取速度,但需要您进行额外的解析,这将使上述优化更难实现。
答案 2 :(得分:2)
尝试使用fread之类加载字符数组的父线程,将1 io中的所有内容作为一个很棒的大字符串加载。
让父级遍历字符串,找到1行,或计算第一行基于大小的位置。将该行的处理交给线程。下一行,冲洗,重复,直到EOF。与线程同步。完成。
答案 3 :(得分:1)
文件I / O可以获得的最佳性能是通过内存映射。 This is an example。我将从单线程设计开始,如果后加载处理被证明是一个瓶颈,那么它就是平行的。