簡體   English   中英

如何確定將 _IONBF 宏與 setvbuf 函數一起使用,文件操作很慢

[英]How to ascertain that using the _IONBF macro with the setvbuf function, file operations are slow

我想有一個明確的例子,實際上在 setvbuf 函數中使用 _IONBF 宏,文件中的寫入操作(流)直接發生,而不使用緩沖區。 如果我在我的文件系統(SSD 內存)中做這個實驗,我不會看到任何寫入延遲,因為它是一個非常快的設備,但如果我使用軟盤來做這個,我將不得不看到,當我運行程序時,我的終端的命令提示符,寫入軟盤結束后立即釋放。

為什么在我看來仍然通過緩沖區進行寫入?

注意:在程序字符串中,我復制/粘貼了一個很長的文本(1.44 MB 字符); 所以如果你想嘗試這個實驗(除了軟盤驅動器),你必須填充足夠的字符串以降低在設備上的寫入速度。

#include <stdio.h>
#include <string.h>

int main() {
    FILE *fp;
    char string[] = "here goes a very long text .... enough to fill a floppy disk!";

    fp = freopen("/Volumes/FLOPPY/file.txt", "w", stdout);
    setvbuf(fp, NULL, _IONBF, 0);
    printf("%s", string);
    printf("\nEND OF FILE");

    fclose(fp);
    return(0);
}




printf()函數可能會將您的請求映射到單個write()調用,不使用緩沖,但也不會減慢速度。 如果想看不緩沖的效果,使用單字符I/O:

for (int i = 0; string[i] != '\0'; i++)
    putc(string[i], fp);

對於無緩沖 I/O,這將顯示差異,因為每次調用putc()需要一個write()系統調用,因為只有一個字節可用於處理。

請注意,下面的代碼不適用於字符串——它適用於字節數組(無空終止符)。 差異對性能並不重要; 它確實需要在處理數據時稍加注意。

該代碼還使用常規fopen()而不是在stdout上使用freopen() 同樣,這不會(極不可能)對性能產生重大影響。

slow11.c

#include <stdio.h>

#define FLOPPY_SIZE (2 * 80 * 18 * 512) // 2 sides, 80 tracks, 18 sectors, 512 bytes

int main(void)
{
    char string[FLOPPY_SIZE];

    for (size_t i = 0; i < FLOPPY_SIZE; i++)
        string[i] = (i % 64) + '0';

    const char filename[] = "floppy.data";
    FILE *fp = fopen(filename, "w");
    setvbuf(fp, NULL, _IONBF, 0);

    for (size_t i = 0; i < FLOPPY_SIZE; i++)
        putc(string[i], fp);

    fclose(fp);

    return(0);
}

slow61.c

我還通過刪除setvbuf()行從slow11.c創建了一個程序slow61.c

fast89.c

#include <stdio.h>

#define FLOPPY_SIZE (2 * 80 * 18 * 512) // 2 sides, 80 tracks, 18 sectors, 512 bytes

int main(void)
{
    char string[FLOPPY_SIZE];

    for (size_t i = 0; i < FLOPPY_SIZE; i++)
        string[i] = (i % 64) + '0';

    const char filename[] = "floppy.data";
    FILE *fp = fopen(filename, "w");
    setvbuf(fp, NULL, _IONBF, 0);

    fprintf(fp, "%.*s", FLOPPY_SIZE, string);

    fclose(fp);

    return(0);
}

示例運行時間

timecmd程序是一個自制程序; -u選項以微秒為單位報告時間( -n表示納秒; -m表示毫秒,整秒什么都沒有)。 它主要用於長時間運行的程序,它有助於了解命令何時開始,以便您可以猜測它何時完成(這就是它報告開始和完成信息的原因)。 您可以改用(POSIX 標准) time 輸出格式會有所不同。

$ for i in 1 2 3 4 5 6 7 8 9 0; do timecmd -u -- fast89; timecmd -u slow61; timecmd -u slow11; done
2020-03-01 07:58:05.964614 [PID 14492] fast89
2020-03-01 07:58:05.978391 [PID 14492; status 0x0000]  -  0.013777s
2020-03-01 07:58:05.986902 [PID 14494] slow61
2020-03-01 07:58:06.058328 [PID 14494; status 0x0000]  -  0.071426s
2020-03-01 07:58:06.066949 [PID 14496] slow11
2020-03-01 07:58:09.788096 [PID 14496; status 0x0000]  -  3.721147s
2020-03-01 07:58:09.795178 [PID 14498] fast89
2020-03-01 07:58:09.806464 [PID 14498; status 0x0000]  -  0.011286s
2020-03-01 07:58:09.813784 [PID 14500] slow61
2020-03-01 07:58:09.882777 [PID 14500; status 0x0000]  -  0.068993s
2020-03-01 07:58:09.890567 [PID 14502] slow11
2020-03-01 07:58:13.689083 [PID 14502; status 0x0000]  -  3.798516s
2020-03-01 07:58:13.696225 [PID 14504] fast89
2020-03-01 07:58:13.708219 [PID 14504; status 0x0000]  -  0.011994s
2020-03-01 07:58:13.715447 [PID 14506] slow61
2020-03-01 07:58:13.784190 [PID 14506; status 0x0000]  -  0.068743s
2020-03-01 07:58:13.791485 [PID 14508] slow11
2020-03-01 07:58:17.495425 [PID 14508; status 0x0000]  -  3.703940s
2020-03-01 07:58:17.502710 [PID 14510] fast89
2020-03-01 07:58:17.514147 [PID 14510; status 0x0000]  -  0.011437s
2020-03-01 07:58:17.521541 [PID 14512] slow61
2020-03-01 07:58:17.589657 [PID 14512; status 0x0000]  -  0.068116s
2020-03-01 07:58:17.596818 [PID 14514] slow11
2020-03-01 07:58:21.253654 [PID 14514; status 0x0000]  -  3.656836s
2020-03-01 07:58:21.260930 [PID 14516] fast89
2020-03-01 07:58:21.272169 [PID 14516; status 0x0000]  -  0.011239s
2020-03-01 07:58:21.279587 [PID 14518] slow61
2020-03-01 07:58:21.348507 [PID 14518; status 0x0000]  -  0.068920s
2020-03-01 07:58:21.355832 [PID 14520] slow11
2020-03-01 07:58:25.041571 [PID 14520; status 0x0000]  -  3.685739s
2020-03-01 07:58:25.048497 [PID 14522] fast89
2020-03-01 07:58:25.059680 [PID 14522; status 0x0000]  -  0.011183s
2020-03-01 07:58:25.066855 [PID 14524] slow61
2020-03-01 07:58:25.135246 [PID 14524; status 0x0000]  -  0.068391s
2020-03-01 07:58:25.142421 [PID 14526] slow11
2020-03-01 07:58:28.853268 [PID 14526; status 0x0000]  -  3.710847s
2020-03-01 07:58:28.860497 [PID 14528] fast89
2020-03-01 07:58:28.872152 [PID 14528; status 0x0000]  -  0.011655s
2020-03-01 07:58:28.879254 [PID 14530] slow61
2020-03-01 07:58:28.947534 [PID 14530; status 0x0000]  -  0.068280s
2020-03-01 07:58:28.955126 [PID 14532] slow11
2020-03-01 07:58:33.236459 [PID 14532; status 0x0000]  -  4.281333s
2020-03-01 07:58:33.243709 [PID 14534] fast89
2020-03-01 07:58:33.260364 [PID 14534; status 0x0000]  -  0.016655s
2020-03-01 07:58:33.267575 [PID 14536] slow61
2020-03-01 07:58:33.336602 [PID 14536; status 0x0000]  -  0.069027s
2020-03-01 07:58:33.344791 [PID 14538] slow11
2020-03-01 07:58:37.065292 [PID 14538; status 0x0000]  -  3.720501s
2020-03-01 07:58:37.072215 [PID 14540] fast89
2020-03-01 07:58:37.083717 [PID 14540; status 0x0000]  -  0.011502s
2020-03-01 07:58:37.090785 [PID 14542] slow61
2020-03-01 07:58:37.158659 [PID 14542; status 0x0000]  -  0.067874s
2020-03-01 07:58:37.165790 [PID 14544] slow11
2020-03-01 07:58:41.024668 [PID 14544; status 0x0000]  -  3.858878s
2020-03-01 07:58:41.032007 [PID 14566] fast89
2020-03-01 07:58:41.043518 [PID 14566; status 0x0000]  -  0.011511s
2020-03-01 07:58:41.053114 [PID 14568] slow61
2020-03-01 07:58:41.128938 [PID 14568; status 0x0000]  -  0.075824s
2020-03-01 07:58:41.136826 [PID 14570] slow11
2020-03-01 07:58:44.971013 [PID 14570; status 0x0000]  -  3.834187s
$

它並不需要太多的技巧地看到, slow11代碼需要大約300倍,只要fast89代碼,也不是說非緩沖的關鍵因素,因為slow61僅約6-7倍,慢如fast89

在運行 macOS Mojave 10.14.6 和 SSD 並使用 GCC 9.2.0 的 MacBook Pro 上進行測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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