簡體   English   中英

如何在c中寫入比fprintf更快的文本文件?

[英]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緩存,因此它可能受益於更大的完全緩沖的寫緩存。

當然,這假設您正在寫一個相對較慢的媒體,並且節省的時間是相關的; 否則,無論什么減慢你的速度都不在這里 ,因此增加保存性能並不會對你有所幫助。

有一些儀器,如profgprof ,可以幫助您確定您的計划花費最多的時間。

一個更尷尬的可能性是將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.所以基本上我已經“發現”了這樣:

  • 8K緩沖區沒有優勢,4K足夠了
  • 我最初使用_IOFBF的建議完全沒有價值,因為系統已經為你做了。 這反過來意味着Kiwi的答案是最正確的 ,正如Andrew所指出的那樣 - 避免了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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM