我必须将一些图形数据(结构数组)保存到文本文件中。我使用 fprintf 制作了工作程序,但为了获得额外的积分,我需要更快。我花了几个小时在谷歌上搜索是否有更快的东西并尝试使用 fwrite (但我无法将 fwrite 作为文本)我真的找不到任何其他功能等。
这是我使用 fprintf 的写函数:
void save_txt(const graph_t * const graph, const char *fname)
{
int count = graph->num_edges, i = 0;
FILE *f = fopen(fname, "w");
while (count > 0) {
int r = fprintf(f, "%d %d %d\n", (graph->edges[i].from), (graph->edges[i].to), (graph->edges[i].cost));
i++;
if (r >= 6) {
count -= 1;
} else {
break;
}
}
if (f) {
fclose(f);
}
}
最佳答案
我会尝试在流上设置一个写缓冲区,并尝试不同大小的缓冲区(例如 1K、2K、4K、8K 等)。请注意,默认情况下您的文件已经在使用 BUFSIZ 值的缓冲区,这可能已经足够了。
#define BUFFERSIZE 0x1000
void save_txt(const graph_t * const graph, const char *fname)
{
int count = graph->num_edges, i = 0;
unsigned char buf[BUFFERSIZE];
FILE *f = fopen(fname, "w");
setvbuf(f, buf, _IOFBF, BUFFERSIZE);
...
输出文件
f
带有默认的 BUFSIZ 缓存,因此它可能受益于更大的全缓冲写入缓存。当然,这假设您正在写入相对较慢的介质,并且节省的时间是相关的;否则,任何让你慢下来的东西 都不在这里 ,因此提高保存性能不会对你有明显的帮助。
有像
prof
和 gprof
这样的工具可以帮助你确定你的程序在哪里花费的时间最多。一种更尴尬的可能性是将 Kiwi 的答案与缓冲写入调用合并,以避免 printf 中验证使用哪种格式的代码,因为您已经知道这一点,并尽可能少地使用 I/O 调用(即使只有一个如果 BUFFERSIZE 大于目标文件的长度)。
// These variables must now be global, declared outside save_txt.
char kiwiBuf[BUFFERSIZE];
size_t kiwiPtr = 0;
FILE *f;
void my_putchar(char c) {
kiwiBuf[kiwiPtr++] = c;
// Is the buffer full?
if (kiwiPtr == BUFFERSIZE) {
// Yes, empty the buffer into the file.
flushBuffer();
}
}
void flushBuffer() {
if (kiwiPtr) {
fwrite(kiwiBuf, kiwiPtr, 1, f);
kiwiPtr = 0;
}
}
您现在需要在关闭之前刷新缓冲区:
void save_txt(const graph_t * const graph, const char *fname)
{
int i, count = graph->num_edges;
f = fopen(fname, "w");
if (NULL == f) {
fprintf(stderr, "Error opening %s\n", fname);
exit(-1);
}
for (i = 0; i < count; i++) {
my_put_nbr(graph->edges[i].from);
my_putchar(' ');
my_put_nbr(graph->edges[i].to);
my_putchar(' ');
my_put_nbr(graph->edges[i].cost);
my_putchar('\n');
}
flushBuffer();
fclose(f);
}
更新
通过将
my_putchar
函数声明为 inline
并使用 4K 缓冲区,上述代码(使用从随机整数数组读取图形的模拟进行修改)比 fprintf
快 6 倍左右Linux mintaka 4.12.8-1-default #1 SMP PREEMPT Thu Aug 17 05:30:12 UTC 2017 (4d7933a) x86_64 x86_64 x86_64 GNU/Linux
gcc version 7.1.1 20170629 [gcc-7-branch revision 249772] (SUSE Linux)
其中大约 2 倍似乎来自缓冲。 Andrew Henle 让我注意到我的代码中有一个错误:我将结果与无缓冲输出的基线进行比较,但
fopen
默认使用 BUFSIZ 值,而我的系统 BUFSIZ 是 8192。所以基本上我“发现”了这一点:printf
的检查和转换。 此外,整体增加(谷歌阿姆达尔定律)取决于节省处理时间的比例。显然,如果一小时的精心制作需要一秒钟的节省,那么节省速度加倍,您就可以节省半秒钟;同时将细化速度提高 1% 可为您节省 36 秒,或 72 倍。
我自己的示例代码被设计为完全面向保存的非常大的图;在这种情况下,写入速度的任何微小改进都可能获得巨大的返回,这在现实世界中可能是不现实的。
另外(在回答评论时),虽然使用足够小的缓冲区会减慢保存速度,但完全不确定使用更大的缓冲区是否会受益。假设整个图总共生成 1.2Kb 的输出;那么当然任何超过 1.2Kb 的缓冲区值都不会产生任何改进。实际上,分配更多内存可能会对性能产生负面影响。
关于c - c - 如何在c中比fprintf更快地写入文本文件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47952423/