[英]How to write text file faster than fprintf in c?
我必須將一些圖形數據(結構數組)保存到文本文件中。 我使用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);
}
UPDATE
通過將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
的檢查和轉換。 此外,總體增長(谷歌Amdahl定律)取決於節省的處理時間的百分比。 顯然,如果一小時的精心設計需要一秒鍾的節省,那么節省的速度加倍可以節省半秒鍾; 同時將精化速度提高1%可以節省36秒或72倍。
我自己的示例代碼被設計為完全以面向對象的方式保存; 在這種情況下,寫作速度的任何微小改進都會帶來潛在的巨大回報,這在現實世界的情況下可能是不現實的。
另外(在回答評論時),雖然使用足夠小的緩沖區會減慢保存速度,但使用更大的緩沖區並不是很有用。 假設整個圖形整體產生1.2Kb的輸出; 那么當然任何高於1.2Kb的緩沖值都不會產生任何改進。 實際上,分配更多內存可能會對性能產生負面影響。
我會寫一個小函數說print_graph(int int int)並直接在其中調用write
或類似的東西,my_putchar是一個寫調用
int my_put_nbr(int nb)
{
if (nb < 0)
{
my_putchar('-');
nb = -nb;
}
if (nb <= 9)
my_putchar(nb + 48);
else
{
my_put_nbr(nb / 10);
my_put_nbr(nb % 10);
}
return (0);
}
我必須比fprintf快1.3倍,這里的代碼對我有用。 我不得不說我必須多次提交它,有時候我通過了相同代碼的5次測試中的1次。 總之,它比fprintf更快但不可靠1.3倍。
void save_txt(const graph_t * const graph, const char *fname)
{
int count = graph->num_edges, i = 0;
char c = '\n';
char d = ' ';
char buffer[15];
FILE *f = fopen(fname, "w");
while (count > 0) {
itoa(graph->edges[i].from,buffer,10);
fputs(buffer, f);
putc(d, f);
itoa(graph->edges[i].to,buffer,10);
fputs(buffer, f);
putc(d, f);
itoa(graph->edges[i].cost,buffer,10);
fputs(buffer, f);
putc(c, f);
i++;
count -= 1;
}
if (f) {
fclose(f);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.