我有一个半个数字的排序向量(用C ++表示)。将其存储到文本文件大约需要10秒钟,并且仅使用50%的CPU(1个核心)。我正在考虑将其并行化,保存2个单独的文件(向量的第一个和第二个半部分),然后连接这些文件。
问题是,除了逐字节读取和加入第一个文件之外,我无法找到任何不同的连接方式......是否存在任何与平台无关的方式(Boost或Windows特定的)有效地加入文件?
答案 0 :(得分:4)
尽管如此,你所说的很少,但强烈地表明编写文本文件的效率非常低。您可能正在使用endl
,这会导致flush
。将其替换为\n
。接下来,如果这不会加快速度,请考虑更简单的数字到文本转换,而不仅仅是使用<<
。我想起了sprintf
。最后,如果您仍处于10秒范围而不是1/10秒范围内,请考虑更严格的优化(例如,在Windows计算机上,您可以在开始时分配具有正确大小的文件,依此类推)。
干杯&amp;第h。,
答案 1 :(得分:0)
连接两个文件可能会花费更多时间,因为典型的文件系统不支持简单的 splice 操作,无法有效地将多个文件拼凑到一个文件中。
虽然有一些方法可以使用多个内核写入文件,但很可能非常好的瓶颈实际上是您的磁盘IO速度。您可以在Linux系统和许多Unix系统上运行vmstat 1
以查看磁盘写入速度。 (以及许多其他整洁的措施。)Windows有一个类似的工具,但我永远不会回想起事情的名称。如果您的写入速度接近磁盘的速度,则可能无法通过添加更多内核来获得更高的性能。
如果你想尝试,有三种方法可行:
open(2)
文件,运行mmap(2)
将其映射到内存中,然后开始复制数据。pwrite(2)
系统调用将数据复制到磁盘,以指定文件中的偏移量以写入该特定数据块aio_write(3)
系统调用来向磁盘提交异步写入。 (我并非确信这实际上会使用多个内核,但库/内核当然可以以这种方式实现它。)前两种方法要求您编写的数据是可预测的大小;如果你真的在写500k数字,它们每个都需要4或8或some other fixed size,这很容易 - 只需将第一个256k数字分配给第一个线程,然后将下一个数字分配给下一个线程,从256*1024*8
个字节开始到文件中。
修改强>
不要忘记旋转硬盘驱动器在寻找驱动器时会有延迟。线性读写模式最适合旋转金属磁盘。我在前两个要点中建议的随机访问机制如果每个都写入不同的磁盘(单个文件很难:)或者你有一个没有寻道延迟的固态硬盘,效果最好。
答案 2 :(得分:0)
我通常会同意你的驱动器是瓶颈 - 但是如果在双核系统中CPU使用率完全 50%,那就意味着CPU确实是问题所在。在这种情况下,字符串转换的数字正在减少。有关优化此功能的提示,请参阅Alf的答案。
并行化,为每个线程提供一个向量块和一个ostream。第一个线程将文件作为其ostream,但其他线程获取内存流。第一个线程完成后,当每个其他线程完成(按顺序)时,将每个内存流写入该文件。
格式化现在是并行完成的,实际的写入文件是序列化的。
答案 3 :(得分:0)
格式化非常昂贵。使用fprintf()vs fwrite()将128M双精度数写入磁盘可以轻松地占用10倍,因为格式化和大量调用(与一个大的fwrite()相比);尝试下面的代码,看看你是否得到类似的时间。文本文件不是处理大量数据的方法;如果你真的不打算坐下来自己阅读,那就不一定是ascii。
如果你做希望保留文本,并且你强加一种严格的格式(例如,所有数字在文件中占用的字节数完全相同),那么你可以分解列表进入大块,并将每个核心格式的一组数字格式化为一个大字符串,并将fseek()放到文件中的适当位置并将其转储出来。您可以使用blocksize来查看内存/性能的最佳权衡。如果你真的受到CPU的瓶颈,这应该允许你通过计算重叠I / O并获得一些胜利。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
/* Jonathan Dursi, SciNet */
#define FILESIZE 1024*1024*128
int write_file_bin(const char *fname, const double *data, const int ndata) {
FILE *fp;
time_t start, end;
fp=fopen(fname,"wb");
assert(fp);
start = time(NULL);
fwrite(data, sizeof(double), ndata, fp);
end = time(NULL);
fclose(fp);
return (int)(end-start);
}
int write_file_ascii(const char *fname, const double *data, const int ndata) {
FILE *fp;
time_t start, end;
int i;
fp=fopen(fname,"wb");
assert(fp);
start = time(NULL);
for (i=0;i<ndata;i++) {
fprintf(fp,"%lf\n",data[i]);
}
end = time(NULL);
fclose(fp);
return (int)(end-start);
}
int main(int argc, char **argv) {
double *data;
int i;
int asciitime, bintime;
data = (double *)malloc(FILESIZE * sizeof(double));
assert(data);
for (i=0;i<FILESIZE;i++) {
data[i] = i*(double)i/2.;
}
asciitime = write_file_ascii("data.txt",data,FILESIZE);
bintime = write_file_bin("data.dat",data,FILESIZE);
printf("Time to write files: ASCII: %d, Binary: %d\n",asciitime, bintime);
return 0;
}